sockaddr_conv.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include <php.h>
  2. #include <php_network.h>
  3. #include "php_sockets.h"
  4. #ifdef PHP_WIN32
  5. #include "windows_common.h"
  6. #else
  7. #include <netdb.h>
  8. #include <arpa/inet.h>
  9. #endif
  10. extern int php_string_to_if_index(const char *val, unsigned *out);
  11. #if HAVE_IPV6
  12. /* Sets addr by hostname, or by ip in string form (AF_INET6) */
  13. int php_set_inet6_addr(struct sockaddr_in6 *sin6, char *string, php_socket *php_sock) /* {{{ */
  14. {
  15. struct in6_addr tmp;
  16. #if HAVE_GETADDRINFO
  17. struct addrinfo hints;
  18. struct addrinfo *addrinfo = NULL;
  19. #endif
  20. char *scope = strchr(string, '%');
  21. if (inet_pton(AF_INET6, string, &tmp)) {
  22. memcpy(&(sin6->sin6_addr.s6_addr), &(tmp.s6_addr), sizeof(struct in6_addr));
  23. } else {
  24. #if HAVE_GETADDRINFO
  25. memset(&hints, 0, sizeof(struct addrinfo));
  26. hints.ai_family = AF_INET6;
  27. #if HAVE_AI_V4MAPPED
  28. hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
  29. #else
  30. hints.ai_flags = AI_ADDRCONFIG;
  31. #endif
  32. getaddrinfo(string, NULL, &hints, &addrinfo);
  33. if (!addrinfo) {
  34. #ifdef PHP_WIN32
  35. PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
  36. #else
  37. PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
  38. #endif
  39. return 0;
  40. }
  41. if (addrinfo->ai_family != PF_INET6 || addrinfo->ai_addrlen != sizeof(struct sockaddr_in6)) {
  42. php_error_docref(NULL, E_WARNING, "Host lookup failed: Non AF_INET6 domain returned on AF_INET6 socket");
  43. freeaddrinfo(addrinfo);
  44. return 0;
  45. }
  46. memcpy(&(sin6->sin6_addr.s6_addr), ((struct sockaddr_in6*)(addrinfo->ai_addr))->sin6_addr.s6_addr, sizeof(struct in6_addr));
  47. freeaddrinfo(addrinfo);
  48. #else
  49. /* No IPv6 specific hostname resolution is available on this system? */
  50. php_error_docref(NULL, E_WARNING, "Host lookup failed: getaddrinfo() not available on this system");
  51. return 0;
  52. #endif
  53. }
  54. if (scope) {
  55. zend_long lval = 0;
  56. double dval = 0;
  57. unsigned scope_id = 0;
  58. scope++;
  59. if (IS_LONG == is_numeric_string(scope, strlen(scope), &lval, &dval, 0)) {
  60. if (lval > 0 && (zend_ulong)lval <= UINT_MAX) {
  61. scope_id = lval;
  62. }
  63. } else {
  64. php_string_to_if_index(scope, &scope_id);
  65. }
  66. sin6->sin6_scope_id = scope_id;
  67. }
  68. return 1;
  69. }
  70. /* }}} */
  71. #endif
  72. /* Sets addr by hostname, or by ip in string form (AF_INET) */
  73. int php_set_inet_addr(struct sockaddr_in *sin, char *string, php_socket *php_sock) /* {{{ */
  74. {
  75. struct in_addr tmp;
  76. struct hostent *host_entry;
  77. #ifdef HAVE_INET_PTON
  78. if (inet_pton(AF_INET, string, &tmp)) {
  79. #else
  80. if (inet_aton(string, &tmp)) {
  81. #endif
  82. sin->sin_addr.s_addr = tmp.s_addr;
  83. } else {
  84. if (strlen(string) > MAXFQDNLEN || ! (host_entry = php_network_gethostbyname(string))) {
  85. /* Note: < -10000 indicates a host lookup error */
  86. #ifdef PHP_WIN32
  87. PHP_SOCKET_ERROR(php_sock, "Host lookup failed", WSAGetLastError());
  88. #else
  89. PHP_SOCKET_ERROR(php_sock, "Host lookup failed", (-10000 - h_errno));
  90. #endif
  91. return 0;
  92. }
  93. if (host_entry->h_addrtype != AF_INET) {
  94. php_error_docref(NULL, E_WARNING, "Host lookup failed: Non AF_INET domain returned on AF_INET socket");
  95. return 0;
  96. }
  97. memcpy(&(sin->sin_addr.s_addr), host_entry->h_addr_list[0], host_entry->h_length);
  98. }
  99. return 1;
  100. }
  101. /* }}} */
  102. /* Sets addr by hostname or by ip in string form (AF_INET or AF_INET6,
  103. * depending on the socket) */
  104. int php_set_inet46_addr(php_sockaddr_storage *ss, socklen_t *ss_len, char *string, php_socket *php_sock) /* {{{ */
  105. {
  106. if (php_sock->type == AF_INET) {
  107. struct sockaddr_in t = {0};
  108. if (php_set_inet_addr(&t, string, php_sock)) {
  109. memcpy(ss, &t, sizeof t);
  110. ss->ss_family = AF_INET;
  111. *ss_len = sizeof(t);
  112. return 1;
  113. }
  114. }
  115. #if HAVE_IPV6
  116. else if (php_sock->type == AF_INET6) {
  117. struct sockaddr_in6 t = {0};
  118. if (php_set_inet6_addr(&t, string, php_sock)) {
  119. memcpy(ss, &t, sizeof t);
  120. ss->ss_family = AF_INET6;
  121. *ss_len = sizeof(t);
  122. return 1;
  123. }
  124. }
  125. #endif
  126. else {
  127. php_error_docref(NULL, E_WARNING,
  128. "IP address used in the context of an unexpected type of socket");
  129. }
  130. return 0;
  131. }