QNIP.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. //
  2. // QNIPV6.m
  3. // HappyDNS
  4. //
  5. // Created by bailong on 16/5/25.
  6. // Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
  7. //
  8. #import <arpa/inet.h>
  9. #import <netdb.h>
  10. #import <netinet/in.h>
  11. #import <unistd.h>
  12. #include <netinet/in.h>
  13. #include <netinet/tcp.h>
  14. #import "QNHex.h"
  15. #import "QNIP.h"
  16. #if __IPHONE_OS_VERSION_MIN_REQUIRED
  17. #import <MobileCoreServices/MobileCoreServices.h>
  18. #import <UIKit/UIKit.h>
  19. #endif
  20. void qn_nat64(char *buf, int buf_size, uint32_t ipv4addr) {
  21. bzero(buf, buf_size);
  22. //nat 4 to ipv6
  23. const char *p = (const char *)&ipv4addr;
  24. const char prefix[] = "64:ff9b::";
  25. memcpy(buf, prefix, sizeof(prefix));
  26. char *phex = buf + sizeof(prefix) - 1;
  27. qn_encodeHexData(phex, p, 2, false);
  28. if (*phex == '0') {
  29. memmove(phex, phex + 1, 3);
  30. phex += 3;
  31. } else {
  32. phex += 4;
  33. }
  34. *phex = ':';
  35. phex++;
  36. qn_encodeHexData(phex, p + 2, 2, false);
  37. if (*phex == '0') {
  38. memmove(phex, phex + 1, 3);
  39. phex[3] = 0;
  40. }
  41. }
  42. int qn_local_ip_internal(char *buf, int buf_size, const char *t_ip) {
  43. struct addrinfo hints = {0}, *ai;
  44. int err = 0;
  45. hints.ai_family = AF_UNSPEC;
  46. hints.ai_socktype = SOCK_DGRAM;
  47. int ret = getaddrinfo(t_ip, "53", &hints, &ai);
  48. if (ret != 0) {
  49. err = errno;
  50. return err;
  51. }
  52. int family = ai->ai_family;
  53. int sock = socket(family, ai->ai_socktype, 0);
  54. if (sock < 0) {
  55. err = errno;
  56. freeaddrinfo(ai);
  57. return err;
  58. }
  59. //fix getaddrinfo bug in ipv4 to ipv6
  60. if (ai->ai_family == AF_INET6) {
  61. ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
  62. }
  63. err = connect(sock, ai->ai_addr, ai->ai_addrlen);
  64. freeaddrinfo(ai);
  65. if (err < 0) {
  66. close(sock);
  67. err = errno;
  68. return err;
  69. }
  70. uint32_t localAddress[16] = {0};
  71. socklen_t addressLength = sizeof(localAddress);
  72. err = getsockname(sock, (struct sockaddr *)&localAddress, &addressLength);
  73. close(sock);
  74. if (err != 0) {
  75. return err;
  76. }
  77. void *addr;
  78. if (family == AF_INET6) {
  79. addr = &((struct sockaddr_in6 *)&localAddress)->sin6_addr;
  80. } else {
  81. addr = &((struct sockaddr_in *)&localAddress)->sin_addr;
  82. }
  83. const char *ip = inet_ntop(family, addr, buf, buf_size);
  84. if (ip == nil) {
  85. return -1;
  86. }
  87. return 0;
  88. }
  89. int qn_localIp(char *buf, int buf_size) {
  90. int ret = qn_local_ip_internal(buf, buf_size, "8.8.8.8");
  91. if (ret != 0) {
  92. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  93. if (![QNIP isIpV6FullySupported]) {
  94. ret = qn_local_ip_internal(buf, buf_size, "64:ff9b::808:808");
  95. }
  96. #endif
  97. }
  98. return ret;
  99. }
  100. @implementation QNIP
  101. + (BOOL)isV6 {
  102. struct addrinfo hints = {0}, *ai;
  103. hints.ai_family = AF_UNSPEC;
  104. hints.ai_socktype = SOCK_STREAM;
  105. int ret = getaddrinfo("8.8.8.8", "http", &hints, &ai);
  106. if (ret != 0) {
  107. return NO;
  108. }
  109. int family = ai->ai_family;
  110. freeaddrinfo(ai);
  111. BOOL result = family == AF_INET6;
  112. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  113. if (![QNIP isIpV6FullySupported] && !ret) {
  114. char buf[64] = {0};
  115. ret = qn_local_ip_internal(buf, sizeof(buf), "64:ff9b::808:808");
  116. if (strchr(buf, ':') != NULL) {
  117. result = YES;
  118. }
  119. }
  120. #endif
  121. return result;
  122. }
  123. + (NSString *)adaptiveIp:(NSString *)ipv4 {
  124. struct addrinfo hints = {0}, *ai;
  125. hints.ai_family = AF_UNSPEC;
  126. hints.ai_socktype = SOCK_STREAM;
  127. int ret = getaddrinfo(ipv4.UTF8String, "http", &hints, &ai);
  128. if (ret != 0) {
  129. return nil;
  130. }
  131. int family = ai->ai_family;
  132. void *addr;
  133. if (family == AF_INET6) {
  134. addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
  135. } else {
  136. addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
  137. }
  138. char buf[64] = {0};
  139. const char *ip = inet_ntop(family, addr, buf, sizeof(buf));
  140. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  141. if (![QNIP isIpV6FullySupported] && family == AF_INET) {
  142. char buf2[64] = {0};
  143. ret = qn_local_ip_internal(buf2, sizeof(buf2), "64:ff9b::808:808");
  144. if (strchr(buf2, ':') != NULL) {
  145. bzero(buf, sizeof(buf));
  146. qn_nat64(buf, sizeof(buf), *((uint32_t *)addr));
  147. }
  148. }
  149. #endif
  150. freeaddrinfo(ai);
  151. return [NSString stringWithUTF8String:ip];
  152. }
  153. + (NSString *)local {
  154. char buf[64] = {0};
  155. int err = qn_localIp(buf, sizeof(buf));
  156. if (err != 0) {
  157. return nil;
  158. }
  159. return [NSString stringWithUTF8String:buf];
  160. }
  161. + (NSString *)ipHost:(NSString *)ip {
  162. NSRange range = [ip rangeOfString:@":"];
  163. if (range.location != NSNotFound) {
  164. return [NSString stringWithFormat:@"[%@]", ip];
  165. }
  166. return ip;
  167. }
  168. + (NSString *)nat64:(NSString *)ip {
  169. struct in_addr s = {0};
  170. inet_pton(AF_INET, ip.UTF8String, (void *)&s);
  171. char buf[64] = {0};
  172. qn_nat64(buf, sizeof(buf), (uint32_t)s.s_addr);
  173. return [NSString stringWithUTF8String:buf];
  174. }
  175. + (BOOL)isIpV6FullySupported {
  176. #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
  177. float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
  178. if (sysVersion < 9.0) {
  179. return NO;
  180. }
  181. #else
  182. NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
  183. if (sysVersion.majorVersion < 10) {
  184. return NO;
  185. } else if (sysVersion.majorVersion == 10) {
  186. return sysVersion.minorVersion >= 11;
  187. }
  188. #endif
  189. return YES;
  190. }
  191. + (BOOL)mayBeIpV4:(NSString *)domain {
  192. NSUInteger l = domain.length;
  193. if (l > 15 || l < 7) {
  194. return NO;
  195. }
  196. const char *str = domain.UTF8String;
  197. if (str == nil) {
  198. return NO;
  199. }
  200. for (const char *p = str; p < str + l; p++) {
  201. if ((*p < '0' || *p > '9') && *p != '.') {
  202. return NO;
  203. }
  204. }
  205. return YES;
  206. }
  207. @end