net_address_private_impl.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright (c) 2012 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 "ppapi/shared_impl/private/net_address_private_impl.h"
6
7#if defined(OS_WIN)
8#include <windows.h>
9#include <winsock2.h>
10#include <ws2tcpip.h>
11#elif defined(OS_POSIX) && !defined(OS_NACL)
12#include <arpa/inet.h>
13#include <sys/socket.h>
14#include <sys/types.h>
15#endif
16
17#include <string.h>
18
19#include <string>
20
21#include "base/basictypes.h"
22#include "base/logging.h"
23#include "base/strings/stringprintf.h"
24#include "build/build_config.h"
25#include "ppapi/c/pp_var.h"
26#include "ppapi/c/private/ppb_net_address_private.h"
27#include "ppapi/shared_impl/proxy_lock.h"
28#include "ppapi/shared_impl/var.h"
29#include "ppapi/thunk/thunk.h"
30
31#if defined(OS_MACOSX)
32// This is a bit evil, but it's standard operating procedure for |s6_addr|....
33#define s6_addr16 __u6_addr.__u6_addr16
34#endif
35
36#if defined(OS_WIN)
37// The type of |sockaddr::sa_family|.
38typedef ADDRESS_FAMILY sa_family_t;
39
40#define s6_addr16 u.Word
41#define ntohs(x) _byteswap_ushort(x)
42#define htons(x) _byteswap_ushort(x)
43#endif  // defined(OS_WIN)
44
45// The net address interface doesn't have a normal C -> C++ thunk since it
46// doesn't actually have any proxy wrapping or associated objects; it's just a
47// call into base. So we implement the entire interface here, using the thunk
48// namespace so it magically gets hooked up in the proper places.
49
50namespace ppapi {
51
52namespace {
53
54// Define our own net-host-net conversion, rather than reuse the one in
55// base/sys_byteorder.h, to simplify the NaCl port. NaCl has no byte swap
56// primitives.
57uint16 ConvertFromNetEndian16(uint16 x) {
58#if defined(ARCH_CPU_LITTLE_ENDIAN)
59  return (x << 8) | (x >> 8);
60#else
61  return x;
62#endif
63}
64
65uint16 ConvertToNetEndian16(uint16 x) {
66#if defined(ARCH_CPU_LITTLE_ENDIAN)
67  return (x << 8) | (x >> 8);
68#else
69  return x;
70#endif
71}
72
73static const size_t kIPv4AddressSize = 4;
74static const size_t kIPv6AddressSize = 16;
75
76// This structure is a platform-independent representation of a network address.
77// It is a private format that we embed in PP_NetAddress_Private and is NOT part
78// of the stable Pepper API.
79struct NetAddress {
80  bool is_valid;
81  bool is_ipv6;  // if true, IPv6, otherwise IPv4.
82  uint16_t port;  // host order, not network order.
83  int32_t flow_info;  // 0 for IPv4
84  int32_t scope_id;   // 0 for IPv4
85  // IPv4 addresses are 4 bytes. IPv6 are 16 bytes. Addresses are stored in net
86  // order (big-endian), which only affects IPv6 addresses, which consist of 8
87  // 16-bit components. These will be byte-swapped on small-endian hosts.
88  uint8_t address[kIPv6AddressSize];
89};
90
91// Make sure that sizeof(NetAddress) is the same for all compilers. This ensures
92// that the alignment is the same on both sides of the NaCl proxy, which is
93// important because we serialize and deserialize PP_NetAddress_Private by
94// simply copying the raw bytes.
95COMPILE_ASSERT(sizeof(NetAddress) == 28,
96               NetAddress_different_for_compiler);
97
98// Make sure the storage in |PP_NetAddress_Private| is big enough. (Do it here
99// since the data is opaque elsewhere.)
100COMPILE_ASSERT(sizeof(reinterpret_cast<PP_NetAddress_Private*>(0)->data) >=
101               sizeof(NetAddress),
102               PP_NetAddress_Private_data_too_small);
103
104size_t GetAddressSize(const NetAddress* net_addr) {
105  return net_addr->is_ipv6 ? kIPv6AddressSize : kIPv4AddressSize;
106}
107
108// Convert to embedded struct if it has been initialized.
109NetAddress* ToNetAddress(PP_NetAddress_Private* addr) {
110  if (!addr || addr->size != sizeof(NetAddress))
111    return NULL;
112  return reinterpret_cast<NetAddress*>(addr->data);
113}
114
115const NetAddress* ToNetAddress(const PP_NetAddress_Private* addr) {
116  return ToNetAddress(const_cast<PP_NetAddress_Private*>(addr));
117}
118
119// Initializes the NetAddress struct embedded in a PP_NetAddress_Private struct.
120// Zeroes the memory, so net_addr->is_valid == false.
121NetAddress* InitNetAddress(PP_NetAddress_Private* addr) {
122  addr->size = sizeof(NetAddress);
123  NetAddress* net_addr = ToNetAddress(addr);
124  DCHECK(net_addr);
125  memset(net_addr, 0, sizeof(NetAddress));
126  return net_addr;
127}
128
129bool IsValid(const NetAddress* net_addr) {
130  return net_addr && net_addr->is_valid;
131}
132
133PP_NetAddressFamily_Private GetFamily(const PP_NetAddress_Private* addr) {
134  const NetAddress* net_addr = ToNetAddress(addr);
135  if (!IsValid(net_addr))
136    return PP_NETADDRESSFAMILY_UNSPECIFIED;
137  return net_addr->is_ipv6 ?
138         PP_NETADDRESSFAMILY_IPV6 : PP_NETADDRESSFAMILY_IPV4;
139}
140
141uint16_t GetPort(const PP_NetAddress_Private* addr) {
142  const NetAddress* net_addr = ToNetAddress(addr);
143  if (!IsValid(net_addr))
144    return 0;
145  return net_addr->port;
146}
147
148PP_Bool GetAddress(const PP_NetAddress_Private* addr,
149                   void* address,
150                   uint16_t address_size) {
151  const NetAddress* net_addr = ToNetAddress(addr);
152  if (!IsValid(net_addr))
153    return PP_FALSE;
154  size_t net_addr_size = GetAddressSize(net_addr);
155  // address_size must be big enough.
156  if (net_addr_size > address_size)
157    return PP_FALSE;
158  memcpy(address, net_addr->address, net_addr_size);
159  return PP_TRUE;
160}
161
162uint32_t GetScopeID(const PP_NetAddress_Private* addr) {
163  const NetAddress* net_addr = ToNetAddress(addr);
164  if (!IsValid(net_addr))
165    return 0;
166  return net_addr->scope_id;
167}
168
169PP_Bool AreHostsEqual(const PP_NetAddress_Private* addr1,
170                      const PP_NetAddress_Private* addr2) {
171  const NetAddress* net_addr1 = ToNetAddress(addr1);
172  const NetAddress* net_addr2 = ToNetAddress(addr2);
173  if (!IsValid(net_addr1) || !IsValid(net_addr2))
174    return PP_FALSE;
175
176  if ((net_addr1->is_ipv6 != net_addr2->is_ipv6) ||
177      (net_addr1->flow_info != net_addr2->flow_info) ||
178      (net_addr1->scope_id != net_addr2->scope_id))
179    return PP_FALSE;
180
181  size_t net_addr_size = GetAddressSize(net_addr1);
182  for (size_t i = 0; i < net_addr_size; i++) {
183    if (net_addr1->address[i] != net_addr2->address[i])
184      return PP_FALSE;
185  }
186
187  return PP_TRUE;
188}
189
190PP_Bool AreEqual(const PP_NetAddress_Private* addr1,
191                 const PP_NetAddress_Private* addr2) {
192  // |AreHostsEqual()| will also validate the addresses and return false if
193  // either is invalid.
194  if (!AreHostsEqual(addr1, addr2))
195    return PP_FALSE;
196
197  // AreHostsEqual has validated these net addresses.
198  const NetAddress* net_addr1 = ToNetAddress(addr1);
199  const NetAddress* net_addr2 = ToNetAddress(addr2);
200  return PP_FromBool(net_addr1->port == net_addr2->port);
201}
202
203std::string ConvertIPv4AddressToString(const NetAddress* net_addr,
204                                       bool include_port) {
205  std::string description = base::StringPrintf(
206      "%u.%u.%u.%u",
207      net_addr->address[0], net_addr->address[1],
208      net_addr->address[2], net_addr->address[3]);
209  if (include_port)
210    base::StringAppendF(&description, ":%u", net_addr->port);
211  return description;
212}
213
214// Format an IPv6 address for human consumption, basically according to RFC
215// 5952.
216//  - If the scope is nonzero, it is appended to the address as "%<scope>" (this
217//    is not in RFC 5952, but consistent with |getnameinfo()| on Linux and
218//    Windows).
219//  - If |include_port| is true, the address (possibly including the scope) is
220//    enclosed in square brackets and ":<port>" is appended, i.e., the overall
221//    format is "[<address>]:<port>".
222//  - If the address is an IPv4 address embedded IPv6 (per RFC 4291), then the
223//    mixed format is used, e.g., "::ffff:192.168.1.2". This is optional per RFC
224//    5952, but consistent with |getnameinfo()|.
225std::string ConvertIPv6AddressToString(const NetAddress* net_addr,
226                                       bool include_port) {
227  std::string description(include_port ? "[" : "");
228
229  const uint16_t* address16 =
230      reinterpret_cast<const uint16_t*>(net_addr->address);
231  // IPv4 address embedded in IPv6.
232  if (address16[0] == 0 && address16[1] == 0 &&
233      address16[2] == 0 && address16[3] == 0 &&
234      address16[4] == 0 &&
235      (address16[5] == 0 || address16[5] == 0xffff)) {
236    base::StringAppendF(
237        &description,
238        address16[5] == 0 ? "::%u.%u.%u.%u" : "::ffff:%u.%u.%u.%u",
239        net_addr->address[12],
240        net_addr->address[13],
241        net_addr->address[14],
242        net_addr->address[15]);
243
244  // "Real" IPv6 addresses.
245  } else {
246    // Find the first longest run of 0s (of length > 1), to collapse to "::".
247    int longest_start = 0;
248    int longest_length = 0;
249    int curr_start = 0;
250    int curr_length = 0;
251    for (int i = 0; i < 8; i++) {
252      if (address16[i] != 0) {
253        curr_length = 0;
254      } else {
255        if (!curr_length)
256          curr_start = i;
257        curr_length++;
258        if (curr_length > longest_length) {
259          longest_start = curr_start;
260          longest_length = curr_length;
261        }
262      }
263    }
264
265    bool need_sep = false;  // Whether the next item needs a ':' to separate.
266    for (int i = 0; i < 8;) {
267      if (longest_length > 1 && i == longest_start) {
268        description.append("::");
269        need_sep = false;
270        i += longest_length;
271      } else {
272        uint16_t v = ConvertFromNetEndian16(address16[i]);
273        base::StringAppendF(&description, need_sep ? ":%x" : "%x", v);
274        need_sep = true;
275        i++;
276      }
277    }
278  }
279
280  // Nonzero scopes, e.g., 123, are indicated by appending, e.g., "%123".
281  if (net_addr->scope_id != 0)
282    base::StringAppendF(&description, "%%%u", net_addr->scope_id);
283
284  if (include_port)
285    base::StringAppendF(&description, "]:%u", net_addr->port);
286
287  return description;
288}
289
290PP_Var Describe(PP_Module /*module*/,
291                const struct PP_NetAddress_Private* addr,
292                PP_Bool include_port) {
293  std::string str = NetAddressPrivateImpl::DescribeNetAddress(
294      *addr, PP_ToBool(include_port));
295  if (str.empty())
296    return PP_MakeUndefined();
297  // We must acquire the lock while accessing the VarTracker, which is part of
298  // the critical section of the proxy which may be accessed by other threads.
299  ProxyAutoLock lock;
300  return StringVar::StringToPPVar(str);
301}
302
303PP_Bool ReplacePort(const struct PP_NetAddress_Private* src_addr,
304                    uint16_t port,
305                    struct PP_NetAddress_Private* dest_addr) {
306  const NetAddress* src_net_addr = ToNetAddress(src_addr);
307  if (!IsValid(src_net_addr) || !dest_addr)
308    return PP_FALSE;
309  dest_addr->size = sizeof(NetAddress);  // make sure 'size' is valid.
310  NetAddress* dest_net_addr = ToNetAddress(dest_addr);
311  *dest_net_addr = *src_net_addr;
312  dest_net_addr->port = port;
313  return PP_TRUE;
314}
315
316void GetAnyAddress(PP_Bool is_ipv6, PP_NetAddress_Private* addr) {
317  if (addr) {
318    NetAddress* net_addr = InitNetAddress(addr);
319    net_addr->is_valid = true;
320    net_addr->is_ipv6 = (is_ipv6 == PP_TRUE);
321  }
322}
323
324void CreateFromIPv4Address(const uint8_t ip[4],
325                           uint16_t port,
326                           struct PP_NetAddress_Private* addr) {
327  if (addr) {
328    NetAddress* net_addr = InitNetAddress(addr);
329    net_addr->is_valid = true;
330    net_addr->is_ipv6 = false;
331    net_addr->port = port;
332    memcpy(net_addr->address, ip, kIPv4AddressSize);
333  }
334}
335
336void CreateFromIPv6Address(const uint8_t ip[16],
337                           uint32_t scope_id,
338                           uint16_t port,
339                           struct PP_NetAddress_Private* addr) {
340  if (addr) {
341    NetAddress* net_addr = InitNetAddress(addr);
342    net_addr->is_valid = true;
343    net_addr->is_ipv6 = true;
344    net_addr->port = port;
345    net_addr->scope_id = scope_id;
346    memcpy(net_addr->address, ip, kIPv6AddressSize);
347  }
348}
349
350const PPB_NetAddress_Private_0_1 net_address_private_interface_0_1 = {
351  &AreEqual,
352  &AreHostsEqual,
353  &Describe,
354  &ReplacePort,
355  &GetAnyAddress
356};
357
358const PPB_NetAddress_Private_1_0 net_address_private_interface_1_0 = {
359  &AreEqual,
360  &AreHostsEqual,
361  &Describe,
362  &ReplacePort,
363  &GetAnyAddress,
364  &GetFamily,
365  &GetPort,
366  &GetAddress
367};
368
369const PPB_NetAddress_Private_1_1 net_address_private_interface_1_1 = {
370  &AreEqual,
371  &AreHostsEqual,
372  &Describe,
373  &ReplacePort,
374  &GetAnyAddress,
375  &GetFamily,
376  &GetPort,
377  &GetAddress,
378  &GetScopeID,
379  &CreateFromIPv4Address,
380  &CreateFromIPv6Address
381};
382
383}  // namespace
384
385namespace thunk {
386
387PPAPI_THUNK_EXPORT const PPB_NetAddress_Private_0_1*
388GetPPB_NetAddress_Private_0_1_Thunk() {
389  return &net_address_private_interface_0_1;
390}
391
392PPAPI_THUNK_EXPORT const PPB_NetAddress_Private_1_0*
393GetPPB_NetAddress_Private_1_0_Thunk() {
394  return &net_address_private_interface_1_0;
395}
396
397PPAPI_THUNK_EXPORT const PPB_NetAddress_Private_1_1*
398GetPPB_NetAddress_Private_1_1_Thunk() {
399  return &net_address_private_interface_1_1;
400}
401
402}  // namespace thunk
403
404// For the NaCl target, all we need are the API functions and the thunk.
405#if !defined(OS_NACL)
406
407// static
408bool NetAddressPrivateImpl::ValidateNetAddress(
409    const PP_NetAddress_Private& addr) {
410  return IsValid(ToNetAddress(&addr));
411}
412
413// static
414bool NetAddressPrivateImpl::SockaddrToNetAddress(
415    const sockaddr* sa,
416    uint32_t sa_length,
417    PP_NetAddress_Private* addr) {
418  if (!sa || sa_length == 0 || !addr)
419    return false;
420
421  // Our platform neutral format stores ports in host order, not net order,
422  // so convert them here.
423  NetAddress* net_addr = InitNetAddress(addr);
424  switch (sa->sa_family) {
425    case AF_INET: {
426      const struct sockaddr_in* addr4 =
427          reinterpret_cast<const struct sockaddr_in*>(sa);
428      net_addr->is_valid = true;
429      net_addr->is_ipv6 = false;
430      net_addr->port = ConvertFromNetEndian16(addr4->sin_port);
431      memcpy(net_addr->address, &addr4->sin_addr.s_addr, kIPv4AddressSize);
432      break;
433    }
434    case AF_INET6: {
435      const struct sockaddr_in6* addr6 =
436          reinterpret_cast<const struct sockaddr_in6*>(sa);
437      net_addr->is_valid = true;
438      net_addr->is_ipv6 = true;
439      net_addr->port = ConvertFromNetEndian16(addr6->sin6_port);
440      net_addr->flow_info = addr6->sin6_flowinfo;
441      net_addr->scope_id = addr6->sin6_scope_id;
442      memcpy(net_addr->address, addr6->sin6_addr.s6_addr, kIPv6AddressSize);
443      break;
444    }
445    default:
446      // InitNetAddress sets net_addr->is_valid to false.
447      return false;
448  }
449  return true;}
450
451// static
452bool NetAddressPrivateImpl::IPEndPointToNetAddress(
453    const std::vector<unsigned char>& address,
454    int port,
455    PP_NetAddress_Private* addr) {
456  if (!addr)
457    return false;
458
459  NetAddress* net_addr = InitNetAddress(addr);
460  switch (address.size()) {
461    case kIPv4AddressSize: {
462      net_addr->is_valid = true;
463      net_addr->is_ipv6 = false;
464      net_addr->port = static_cast<uint16_t>(port);
465      std::copy(address.begin(), address.end(), net_addr->address);
466      break;
467    }
468    case kIPv6AddressSize: {
469      net_addr->is_valid = true;
470      net_addr->is_ipv6 = true;
471      net_addr->port = static_cast<uint16_t>(port);
472      std::copy(address.begin(), address.end(), net_addr->address);
473      break;
474    }
475    default:
476      // InitNetAddress sets net_addr->is_valid to false.
477      return false;
478  }
479
480  return true;
481}
482
483// static
484bool NetAddressPrivateImpl::NetAddressToIPEndPoint(
485    const PP_NetAddress_Private& addr,
486    std::vector<unsigned char>* address,
487    int* port) {
488  if (!address || !port)
489    return false;
490
491  const NetAddress* net_addr = ToNetAddress(&addr);
492  if (!IsValid(net_addr))
493    return false;
494
495  *port = net_addr->port;
496  size_t address_size = GetAddressSize(net_addr);
497  address->assign(&net_addr->address[0], &net_addr->address[address_size]);
498
499  return true;
500}
501#endif  // !defined(OS_NACL)
502
503// static
504std::string NetAddressPrivateImpl::DescribeNetAddress(
505    const PP_NetAddress_Private& addr,
506    bool include_port) {
507  const NetAddress* net_addr = ToNetAddress(&addr);
508  if (!IsValid(net_addr))
509    return std::string();
510
511  // On Windows, |NetAddressToString()| doesn't work in the sandbox. On Mac,
512  // the output isn't consistent with RFC 5952, at least on Mac OS 10.6:
513  // |getnameinfo()| collapses length-one runs of zeros (and also doesn't
514  // display the scope).
515  if (net_addr->is_ipv6)
516    return ConvertIPv6AddressToString(net_addr, include_port);
517  return ConvertIPv4AddressToString(net_addr, include_port);
518}
519
520// static
521void NetAddressPrivateImpl::CreateNetAddressPrivateFromIPv4Address(
522    const PP_NetAddress_IPv4_Dev& ipv4_addr,
523    PP_NetAddress_Private* addr) {
524  CreateFromIPv4Address(ipv4_addr.addr, ConvertFromNetEndian16(ipv4_addr.port),
525                        addr);
526}
527
528// static
529void NetAddressPrivateImpl::CreateNetAddressPrivateFromIPv6Address(
530    const PP_NetAddress_IPv6_Dev& ipv6_addr,
531    PP_NetAddress_Private* addr) {
532  CreateFromIPv6Address(ipv6_addr.addr, 0,
533                        ConvertFromNetEndian16(ipv6_addr.port), addr);
534}
535
536// static
537PP_NetAddress_Family_Dev NetAddressPrivateImpl::GetFamilyFromNetAddressPrivate(
538    const PP_NetAddress_Private& addr) {
539  const NetAddress* net_addr = ToNetAddress(&addr);
540  if (!IsValid(net_addr))
541    return PP_NETADDRESS_FAMILY_UNSPECIFIED;
542  return net_addr->is_ipv6 ? PP_NETADDRESS_FAMILY_IPV6 :
543                             PP_NETADDRESS_FAMILY_IPV4;
544}
545
546// static
547bool NetAddressPrivateImpl::DescribeNetAddressPrivateAsIPv4Address(
548   const PP_NetAddress_Private& addr,
549   PP_NetAddress_IPv4_Dev* ipv4_addr) {
550  if (!ipv4_addr)
551    return false;
552
553  const NetAddress* net_addr = ToNetAddress(&addr);
554  if (!IsValid(net_addr) || net_addr->is_ipv6)
555    return false;
556
557  ipv4_addr->port = ConvertToNetEndian16(net_addr->port);
558
559  COMPILE_ASSERT(sizeof(ipv4_addr->addr) == kIPv4AddressSize,
560                 mismatched_IPv4_address_size);
561  memcpy(ipv4_addr->addr, net_addr->address, kIPv4AddressSize);
562
563  return true;
564}
565
566// static
567bool NetAddressPrivateImpl::DescribeNetAddressPrivateAsIPv6Address(
568    const PP_NetAddress_Private& addr,
569    PP_NetAddress_IPv6_Dev* ipv6_addr) {
570  if (!ipv6_addr)
571    return false;
572
573  const NetAddress* net_addr = ToNetAddress(&addr);
574  if (!IsValid(net_addr) || !net_addr->is_ipv6)
575    return false;
576
577  ipv6_addr->port = ConvertToNetEndian16(net_addr->port);
578
579  COMPILE_ASSERT(sizeof(ipv6_addr->addr) == kIPv6AddressSize,
580                 mismatched_IPv6_address_size);
581  memcpy(ipv6_addr->addr, net_addr->address, kIPv6AddressSize);
582
583  return true;
584}
585
586}  // namespace ppapi
587