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_PRIVATE_UNSPECIFIED; 137 return net_addr->is_ipv6 ? 138 PP_NETADDRESSFAMILY_PRIVATE_IPV6 : PP_NETADDRESSFAMILY_PRIVATE_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& 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& 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 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* 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* 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