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