OSSIPv6Adapter.m 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //
  2. // OSSIPv6Adapter.m
  3. //
  4. // Created by lingkun on 16/5/16.
  5. // Copyright © 2016 Ali. All rights reserved.
  6. //
  7. #import <Foundation/Foundation.h>
  8. #import "OSSIPv6Adapter.h"
  9. #import "OSSIPv6PrefixResolver.h"
  10. #import "OSSReachabilityManager.h"
  11. #import "OSSLog.h"
  12. #include <arpa/inet.h>
  13. #include <dns.h>
  14. #include <err.h>
  15. #include <ifaddrs.h>
  16. #include <net/if.h>
  17. #include <netdb.h>
  18. #include <netinet/in.h>
  19. #include <resolv.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/socket.h>
  23. #include <sys/sysctl.h>
  24. #if TARGET_OS_IOS
  25. #import <UIKit/UIApplication.h>
  26. #elif TARGET_OS_OSX
  27. #import <AppKit/NSApplication.h>
  28. #endif
  29. #define UNKNOWN_STACK 0
  30. #define SUPPORT_IPV4_STACK 1
  31. #define SUPPORT_IPV6_STACK 2
  32. #define ROUNDUP_LEN(a) \
  33. ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  34. #define TypeEN "en0"
  35. #define IOS_9_VERSION @"9.0"
  36. @implementation OSSIPv6Adapter
  37. {
  38. BOOL isIPv6Only;
  39. BOOL isIPv6OnlyResolved;
  40. }
  41. - (instancetype)init {
  42. if (self = [super init]) {
  43. isIPv6Only = NO;
  44. isIPv6OnlyResolved = NO;
  45. NSString *notificationName;
  46. #if TARGET_OS_IOS
  47. notificationName = UIApplicationDidBecomeActiveNotification;
  48. #elif TARGET_OS_OSX
  49. notificationName = NSApplicationDidBecomeActiveNotification;
  50. #endif
  51. // When App switches to active status, refresh the IPv6-only check.
  52. NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
  53. [defaultCenter addObserver:self
  54. selector:@selector(appDidBecomeActiveFunc)
  55. name:notificationName
  56. object:nil];
  57. }
  58. return self;
  59. }
  60. + (instancetype)getInstance {
  61. static id singletonInstance = nil;
  62. static dispatch_once_t once_token;
  63. dispatch_once(&once_token, ^{
  64. if (!singletonInstance) {
  65. singletonInstance = [[super allocWithZone:NULL] init];
  66. }
  67. });
  68. return singletonInstance;
  69. }
  70. - (BOOL)isIPv6OnlyNetwork {
  71. @synchronized(self) {
  72. if (isIPv6OnlyResolved) {
  73. return isIPv6Only;
  74. }
  75. OSSLogDebug(@"Start resolved network to see if in IPv6-Only env.");
  76. int localStack = 0;
  77. localStack = SUPPORT_IPV4_STACK | SUPPORT_IPV6_STACK;
  78. localStack &= [self getDNSServersIpStack];
  79. if (localStack & SUPPORT_IPV4_STACK) {
  80. // support IPv4
  81. isIPv6Only = NO;
  82. } else if (localStack & SUPPORT_IPV6_STACK) {
  83. // IPv6-Only
  84. isIPv6Only = YES;
  85. [[OSSIPv6PrefixResolver getInstance] updateIPv6Prefix];
  86. } else {
  87. OSSLogDebug(@"[%s]: Error.", __FUNCTION__);
  88. isIPv6Only = NO;
  89. }
  90. isIPv6OnlyResolved = YES;
  91. if (isIPv6Only) {
  92. OSSLogDebug(@"[%s]: IPv6-Only network now.", __FUNCTION__);
  93. } else {
  94. OSSLogDebug(@"[%s]: Not IPv6-Only network now.", __FUNCTION__);
  95. }
  96. return isIPv6Only;
  97. }
  98. }
  99. - (void)appDidBecomeActiveFunc {
  100. OSSLogDebug(@"[%s]: App become active, refresh IPv6-Only status.", __FUNCTION__);
  101. [self reResolveIPv6OnlyStatus];
  102. }
  103. - (BOOL)reResolveIPv6OnlyStatus {
  104. isIPv6OnlyResolved = NO;
  105. return [self isIPv6OnlyNetwork];
  106. }
  107. - (NSString *)handleIpv4Address:(NSString *)addr {
  108. if (addr == nil || addr.length == 0) {
  109. return nil;
  110. }
  111. if ([self isIPv6Address:addr]) return [NSString stringWithFormat:@"[%@]", addr];
  112. NSString *convertedAddr;
  113. if ([self isIPv6OnlyNetwork]) {
  114. convertedAddr = [[OSSIPv6PrefixResolver getInstance] convertIPv4toIPv6:addr];
  115. return [NSString stringWithFormat:@"[%@]", convertedAddr];
  116. } else {
  117. convertedAddr = addr;
  118. }
  119. return convertedAddr;
  120. }
  121. /**
  122. * @brief Looks up the DNS server stack and returns the flag combinations of SUPPORT_IPV4_STACK and SUPPORT_IPV6_STACK.
  123. *
  124. * @return the flag combinations of SUPPORT_IPV4_STACK and SUPPORT_IPV6_STACK
  125. */
  126. - (int)getDNSServersIpStack {
  127. int dns_stack = 0;
  128. res_state res = malloc(sizeof(struct __res_state));
  129. int result = res_ninit(res);
  130. if (result == 0) {
  131. union res_9_sockaddr_union *addr_union = malloc(res->nscount * sizeof(union res_9_sockaddr_union));
  132. res_getservers(res, addr_union, res->nscount);
  133. for (int i = 0; i < res->nscount; i++) {
  134. if (addr_union[i].sin.sin_family == AF_INET) {
  135. char ip[INET_ADDRSTRLEN];
  136. if (inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN)) {
  137. dns_stack |= SUPPORT_IPV4_STACK;
  138. }
  139. } else if (addr_union[i].sin6.sin6_family == AF_INET6) {
  140. char ip[INET6_ADDRSTRLEN];
  141. if (inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN)) {
  142. dns_stack |= SUPPORT_IPV6_STACK;
  143. }
  144. } else {
  145. OSSLogDebug(@"%s: Undefined family.", __FUNCTION__);
  146. }
  147. }
  148. free(addr_union);
  149. }
  150. res_ndestroy(res);
  151. free(res);
  152. return dns_stack;
  153. }
  154. - (BOOL)isIPv4Address:(NSString *)addr {
  155. if (addr == nil) {
  156. return NO;
  157. }
  158. const char *utf8 = [addr UTF8String];
  159. // Check valid IPv4.
  160. struct in_addr dst;
  161. int success = inet_pton(AF_INET, utf8, &(dst.s_addr));
  162. return success == 1;
  163. }
  164. - (BOOL)isIPv6Address:(NSString *)addr {
  165. if (addr == nil) {
  166. return NO;
  167. }
  168. const char *utf8 = [addr UTF8String];
  169. // Check valid IPv6.
  170. struct in6_addr dst6;
  171. int success = inet_pton(AF_INET6, utf8, &dst6);
  172. return (success == 1);
  173. }
  174. @end