QNDnsPrefetch.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. //
  2. // QNDnsPrefetch.m
  3. // QnDNS
  4. //
  5. // Created by yangsen on 2020/3/26.
  6. // Copyright © 2020 com.qiniu. All rights reserved.
  7. //
  8. #import "QNDnsPrefetch.h"
  9. #import "QNInetAddress.h"
  10. #import "QNDnsCacheInfo.h"
  11. #import "QNZoneInfo.h"
  12. #import "QNDefine.h"
  13. #import "QNConfig.h"
  14. #import "QNDnsCacheFile.h"
  15. #import "QNUtils.h"
  16. #import "QNAsyncRun.h"
  17. #import "QNFixedZone.h"
  18. #import "QNAutoZone.h"
  19. #import <HappyDNS/HappyDNS.h>
  20. //MARK: -- 缓存模型
  21. @interface QNDnsNetworkAddress : NSObject<QNIDnsNetworkAddress>
  22. @property(nonatomic, copy)NSString *hostValue;
  23. @property(nonatomic, copy)NSString *ipValue;
  24. @property(nonatomic, strong)NSNumber *ttlValue;
  25. @property(nonatomic, copy)NSString *sourceValue;
  26. @property(nonatomic, strong)NSNumber *timestampValue;
  27. /// 构造方法 addressData为json String / Dictionary / Data / 遵循 QNIDnsNetworkAddress的实例
  28. + (instancetype)inetAddress:(id)addressInfo;
  29. /// 是否有效,根据时间戳判断
  30. - (BOOL)isValid;
  31. /// 对象转json
  32. - (NSString *)toJsonInfo;
  33. /// 对象转字典
  34. - (NSDictionary *)toDictionary;
  35. @end
  36. @implementation QNDnsNetworkAddress
  37. + (instancetype)inetAddress:(id)addressInfo{
  38. NSDictionary *addressDic = nil;
  39. if ([addressInfo isKindOfClass:[NSDictionary class]]) {
  40. addressDic = (NSDictionary *)addressInfo;
  41. } else if ([addressInfo isKindOfClass:[NSString class]]){
  42. NSData *data = [(NSString *)addressInfo dataUsingEncoding:NSUTF8StringEncoding];
  43. addressDic = [NSJSONSerialization JSONObjectWithData:data
  44. options:NSJSONReadingMutableLeaves
  45. error:nil];
  46. } else if ([addressInfo isKindOfClass:[NSData class]]) {
  47. addressDic = [NSJSONSerialization JSONObjectWithData:(NSData *)addressInfo
  48. options:NSJSONReadingMutableLeaves
  49. error:nil];
  50. } else if ([addressInfo conformsToProtocol:@protocol(QNIDnsNetworkAddress)]){
  51. id <QNIDnsNetworkAddress> address = (id <QNIDnsNetworkAddress> )addressInfo;
  52. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  53. if ([address respondsToSelector:@selector(hostValue)] && [address hostValue]) {
  54. dic[@"hostValue"] = [address hostValue];
  55. }
  56. if ([address respondsToSelector:@selector(ipValue)] && [address ipValue]) {
  57. dic[@"ipValue"] = [address ipValue];
  58. }
  59. if ([address respondsToSelector:@selector(ttlValue)] && [address ttlValue]) {
  60. dic[@"ttlValue"] = [address ttlValue];
  61. }
  62. if ([address respondsToSelector:@selector(sourceValue)] && [address sourceValue]) {
  63. dic[@"sourceValue"] = [address sourceValue];
  64. } else {
  65. dic[@"sourceValue"] = kQNDnsSourceCustom;
  66. }
  67. if ([address respondsToSelector:@selector(timestampValue)] && [address timestampValue]) {
  68. dic[@"timestampValue"] = [address timestampValue];
  69. }
  70. addressDic = [dic copy];
  71. }
  72. if (addressDic) {
  73. QNDnsNetworkAddress *address = [[QNDnsNetworkAddress alloc] init];
  74. [address setValuesForKeysWithDictionary:addressDic];
  75. return address;
  76. } else {
  77. return nil;
  78. }
  79. }
  80. /// 过了 ttl 时间则需要刷新
  81. - (BOOL)needRefresh{
  82. if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) {
  83. return NO;
  84. }
  85. NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
  86. return currentTimestamp > (self.timestampValue.doubleValue + self.ttlValue.doubleValue);
  87. }
  88. /// 只要在最大 ttl 时间内,即为有效
  89. - (BOOL)isValid{
  90. if (!self.timestampValue || !self.ipValue || self.ipValue.length == 0) {
  91. return NO;
  92. }
  93. NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970];
  94. return currentTimestamp < (self.timestampValue.doubleValue + kQNGlobalConfiguration.dnsCacheMaxTTL);
  95. }
  96. - (NSString *)toJsonInfo{
  97. NSString *defaultString = @"{}";
  98. NSDictionary *infoDic = [self toDictionary];
  99. if (!infoDic) {
  100. return defaultString;
  101. }
  102. NSData *infoData = [NSJSONSerialization dataWithJSONObject:infoDic
  103. options:NSJSONWritingPrettyPrinted
  104. error:nil];
  105. if (!infoData) {
  106. return defaultString;
  107. }
  108. NSString *infoStr = [[NSString alloc] initWithData:infoData encoding:NSUTF8StringEncoding];
  109. if (!infoStr) {
  110. return defaultString;
  111. } else {
  112. return infoStr;
  113. }
  114. }
  115. - (NSDictionary *)toDictionary{
  116. return [self dictionaryWithValuesForKeys:@[@"ipValue", @"hostValue", @"ttlValue", @"sourceValue", @"timestampValue"]];
  117. }
  118. - (void)setValue:(id)value forUndefinedKey:(NSString *)key{}
  119. @end
  120. //MARK: -- HappyDNS 适配
  121. @interface QNRecord(DNS)<QNIDnsNetworkAddress>
  122. @end
  123. @implementation QNRecord(DNS)
  124. - (NSString *)hostValue{
  125. return nil;
  126. }
  127. - (NSString *)ipValue{
  128. return self.value;
  129. }
  130. - (NSNumber *)ttlValue{
  131. return @(self.ttl);
  132. }
  133. - (NSNumber *)timestampValue{
  134. return @(self.timeStamp);
  135. }
  136. - (NSString *)sourceValue{
  137. if (self.source == QNRecordSourceSystem) {
  138. return kQNDnsSourceSystem;
  139. } else if (self.source == QNRecordSourceDoh) {
  140. return [NSString stringWithFormat:@"%@<%@>", kQNDnsSourceDoh, self.server];
  141. } else if (self.source == QNRecordSourceUdp) {
  142. return [NSString stringWithFormat:@"%@<%@>", kQNDnsSourceUdp, self.server];
  143. } else if (self.source == QNRecordSourceDnspodEnterprise) {
  144. return kQNDnsSourceDnspod;
  145. } else if (self.ipValue == nil || self.ipValue.length == 0) {
  146. return kQNDnsSourceNone;
  147. } else {
  148. return kQNDnsSourceCustom;
  149. }
  150. }
  151. @end
  152. @interface QNInternalDns : NSObject
  153. @property(nonatomic, strong)id<QNDnsDelegate> dns;
  154. @property(nonatomic, strong)id<QNResolverDelegate> resolver;
  155. @end
  156. @implementation QNInternalDns
  157. + (instancetype)dnsWithDns:(id<QNDnsDelegate>)dns {
  158. QNInternalDns *interDns = [[QNInternalDns alloc] init];
  159. interDns.dns = dns;
  160. return interDns;
  161. }
  162. + (instancetype)dnsWithResolver:(id<QNResolverDelegate>)resolver {
  163. QNInternalDns *interDns = [[QNInternalDns alloc] init];
  164. interDns.resolver = resolver;
  165. return interDns;
  166. }
  167. - (NSArray < id <QNIDnsNetworkAddress> > *)query:(NSString *)host error:(NSError **)error {
  168. if (self.dns && [self.dns respondsToSelector:@selector(query:)]) {
  169. return [self.dns query:host];
  170. } else if (self.resolver) {
  171. NSArray <QNRecord *>* records = [self.resolver query:[[QNDomain alloc] init:host] networkInfo:nil error:error];
  172. return [self filterRecords:records];
  173. }
  174. return nil;
  175. }
  176. - (NSArray <QNRecord *>*)filterRecords:(NSArray <QNRecord *>*)records {
  177. NSMutableArray <QNRecord *> *newRecords = [NSMutableArray array];
  178. for (QNRecord *record in records) {
  179. if (record.type == kQNTypeA || record.type == kQNTypeAAAA) {
  180. [newRecords addObject:record];
  181. }
  182. }
  183. return [newRecords copy];
  184. }
  185. @end
  186. //MARK: -- DNS Prefetcher
  187. @interface QNDnsPrefetch()
  188. // dns 预解析超时,默认3s
  189. @property(nonatomic, assign)int dnsPrefetchTimeout;
  190. // 最近一次预取错误信息
  191. @property(nonatomic, copy)NSString *lastPrefetchedErrorMessage;
  192. /// 是否正在预取,正在预取会直接取消新的预取操作请求
  193. @property(atomic, assign)BOOL isPrefetching;
  194. /// 获取AutoZone时的同步锁
  195. @property(nonatomic, strong)dispatch_semaphore_t getAutoZoneSemaphore;
  196. /// DNS信息本地缓存key
  197. @property(nonatomic, strong)QNDnsCacheInfo *dnsCacheInfo;
  198. // 用户定制 dns
  199. @property(nonatomic, strong)QNInternalDns *customDns;
  200. // 系统 dns
  201. @property(nonatomic, strong)QNInternalDns *systemDns;
  202. /// prefetch hosts
  203. @property(nonatomic, strong)NSMutableSet *prefetchHosts;
  204. /// 缓存DNS解析结果
  205. /// 线程安全:内部方法均是在同一线程执行,读写不必加锁,对外开放接口读操作 需要和内部写操作枷锁
  206. @property(nonatomic, strong)NSMutableDictionary <NSString *, NSArray<QNDnsNetworkAddress *>*> *addressDictionary;
  207. @property(nonatomic, strong)QNDnsCacheFile *diskCache;
  208. @end
  209. @implementation QNDnsPrefetch
  210. + (instancetype)shared{
  211. static QNDnsPrefetch *prefetcher = nil;
  212. static dispatch_once_t onceToken;
  213. dispatch_once(&onceToken, ^{
  214. prefetcher = [[QNDnsPrefetch alloc] init];
  215. });
  216. return prefetcher;
  217. }
  218. - (instancetype)init{
  219. if (self = [super init]) {
  220. _isPrefetching = NO;
  221. _dnsPrefetchTimeout = 3;
  222. }
  223. return self;
  224. }
  225. //MARK: -- uploadManager初始化时,加载本地缓存到内存
  226. /// 同步本地预取缓存 如果存在且满足使用返回false,反之为true
  227. - (BOOL)recoverCache{
  228. id <QNRecorderDelegate> recorder = nil;
  229. NSError *error;
  230. recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir
  231. error:&error];
  232. if (error) {
  233. return YES;
  234. }
  235. NSData *data = [recorder get:[QNIP local]];
  236. if (!data) {
  237. return YES;
  238. }
  239. QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:data];
  240. if (!cacheInfo) {
  241. return YES;
  242. }
  243. NSString *localIp = [QNIP local];
  244. if (!localIp || localIp.length == 0 || ![cacheInfo.localIp isEqualToString:localIp]) {
  245. return YES;
  246. }
  247. [self setDnsCacheInfo:cacheInfo];
  248. return [self recoverDnsCache:cacheInfo.info];
  249. }
  250. /// 本地缓存读取失败后,加载本地域名,预取DNS解析信息
  251. - (void)localFetch{
  252. if ([self prepareToPreFetch] == NO) {
  253. return;
  254. }
  255. NSArray *hosts = [self getLocalPreHost];
  256. @synchronized (self) {
  257. [self.prefetchHosts addObjectsFromArray:hosts];
  258. }
  259. [self preFetchHosts:hosts];
  260. [self recorderDnsCache];
  261. [self endPreFetch];
  262. }
  263. //MARK: -- 检测并预取
  264. /// 根据token检测Dns缓存信息时效,无效则预取。 完成预取操作返回YES,反之返回NO
  265. - (void)checkAndPrefetchDnsIfNeed:(QNZone *)currentZone token:(QNUpToken *)token{
  266. if ([self prepareToPreFetch] == NO) {
  267. return;
  268. }
  269. NSArray *hosts = [self getCurrentZoneHosts:currentZone token:token];
  270. if (hosts == nil) {
  271. return;
  272. }
  273. @synchronized (self) {
  274. [self.prefetchHosts addObjectsFromArray:hosts];
  275. }
  276. [self preFetchHosts:hosts];
  277. [self recorderDnsCache];
  278. [self endPreFetch];
  279. }
  280. /// 检测已预取dns是否还有效,无效则重新预取
  281. - (void)checkWhetherCachedDnsValid{
  282. if ([self prepareToPreFetch] == NO) {
  283. return;
  284. }
  285. NSArray *hosts = nil;
  286. @synchronized (self) {
  287. hosts = [self.prefetchHosts allObjects];
  288. }
  289. [self preFetchHosts:hosts];
  290. [self recorderDnsCache];
  291. [self endPreFetch];
  292. }
  293. //MARK: -- 读取缓存的DNS信息
  294. /// 根据host从缓存中读取DNS信息
  295. - (NSArray <id <QNIDnsNetworkAddress> > *)getInetAddressByHost:(NSString *)host{
  296. if ([self isDnsOpen] == NO) {
  297. return nil;
  298. }
  299. [self clearDnsCacheIfNeeded];
  300. NSArray <QNDnsNetworkAddress *> *addressList = nil;
  301. @synchronized (self) {
  302. addressList = self.addressDictionary[host];
  303. }
  304. if (addressList && addressList.count > 0 && [addressList.firstObject isValid]) {
  305. return addressList;
  306. } else {
  307. return nil;
  308. }
  309. }
  310. - (void)invalidNetworkAddressOfHost:(NSString *)host {
  311. if (host == nil || host.length == 0) {
  312. return;
  313. }
  314. @synchronized (self) {
  315. [self.addressDictionary removeObjectForKey:host];
  316. }
  317. }
  318. - (void)clearDnsCache:(NSError *__autoreleasing _Nullable *)error {
  319. [self clearDnsMemoryCache];
  320. [self clearDnsDiskCache:error];
  321. }
  322. //MARK: --
  323. //MARK: -- 根据dns预取
  324. - (NSString *)prefetchHostBySafeDns:(NSString *)host error:(NSError * __autoreleasing *)error {
  325. if (host == nil) {
  326. return nil;
  327. }
  328. [self invalidNetworkAddressOfHost:host];
  329. NSError *err = nil;
  330. NSArray *nextFetchHosts = @[host];
  331. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.customDns error:&err];
  332. if (nextFetchHosts.count == 0) {
  333. return [self getInetAddressByHost:host].firstObject.sourceValue;
  334. }
  335. if (!kQNGlobalConfiguration.dohEnable) {
  336. if (error != nil && err) {
  337. *error = err;
  338. }
  339. return nil;
  340. }
  341. QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
  342. QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
  343. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:&err];
  344. if (nextFetchHosts.count == 0) {
  345. return [self getInetAddressByHost:host].firstObject.sourceValue;
  346. }
  347. if (error != nil && err) {
  348. *error = err;
  349. }
  350. if ([QNIP isIpV6FullySupported]) {
  351. QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
  352. QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
  353. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:&err];
  354. if (error != nil && err) {
  355. *error = err;
  356. }
  357. }
  358. if (nextFetchHosts.count == 0) {
  359. return [self getInetAddressByHost:host].firstObject.sourceValue;
  360. } else {
  361. return nil;
  362. }
  363. }
  364. - (BOOL)prepareToPreFetch {
  365. if ([self isDnsOpen] == NO) {
  366. return NO;
  367. }
  368. self.lastPrefetchedErrorMessage = nil;
  369. if (self.isPrefetching == YES) {
  370. return NO;
  371. }
  372. [self clearDnsCacheIfNeeded];
  373. self.isPrefetching = YES;
  374. return YES;
  375. }
  376. - (void)endPreFetch{
  377. self.isPrefetching = NO;
  378. }
  379. - (void)preFetchHosts:(NSArray <NSString *> *)fetchHosts {
  380. NSError *err = nil;
  381. [self preFetchHosts:fetchHosts error:&err];
  382. self.lastPrefetchedErrorMessage = err.description;
  383. }
  384. - (void)preFetchHosts:(NSArray <NSString *> *)fetchHosts error:(NSError **)error {
  385. NSArray *nextFetchHosts = fetchHosts;
  386. // 定制
  387. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.customDns error:error];
  388. if (nextFetchHosts.count == 0) {
  389. return;
  390. }
  391. // 系统
  392. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:self.systemDns error:error];
  393. if (nextFetchHosts.count == 0) {
  394. return;
  395. }
  396. // doh
  397. if (kQNGlobalConfiguration.dohEnable) {
  398. QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
  399. QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
  400. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:error];
  401. if (nextFetchHosts.count == 0) {
  402. return;
  403. }
  404. if ([QNIP isIpV6FullySupported]) {
  405. QNDohResolver *dohResolver = [QNDohResolver resolverWithServers:kQNGlobalConfiguration.dohIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
  406. QNInternalDns *doh = [QNInternalDns dnsWithResolver:dohResolver];
  407. nextFetchHosts = [self preFetchHosts:nextFetchHosts dns:doh error:error];
  408. if (nextFetchHosts.count == 0) {
  409. return;
  410. }
  411. }
  412. }
  413. // udp
  414. if (kQNGlobalConfiguration.udpDnsEnable) {
  415. QNDnsUdpResolver *udpDnsResolver = [QNDnsUdpResolver resolverWithServerIPs:kQNGlobalConfiguration.udpDnsIpv4Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
  416. QNInternalDns *udpDns = [QNInternalDns dnsWithResolver:udpDnsResolver];
  417. [self preFetchHosts:nextFetchHosts dns:udpDns error:error];
  418. if ([QNIP isIpV6FullySupported]) {
  419. QNDnsUdpResolver *udpDnsResolver = [QNDnsUdpResolver resolverWithServerIPs:kQNGlobalConfiguration.udpDnsIpv6Servers recordType:kQNTypeA timeout:kQNGlobalConfiguration.dnsResolveTimeout];
  420. QNInternalDns *udpDns = [QNInternalDns dnsWithResolver:udpDnsResolver];
  421. [self preFetchHosts:nextFetchHosts dns:udpDns error:error];
  422. }
  423. }
  424. }
  425. - (NSArray *)preFetchHosts:(NSArray <NSString *> *)preHosts dns:(QNInternalDns *)dns error:(NSError **)error {
  426. if (!preHosts || preHosts.count == 0) {
  427. return nil;
  428. }
  429. if (!dns) {
  430. return [preHosts copy];
  431. }
  432. int dnsRepreHostNum = kQNGlobalConfiguration.dnsRepreHostNum;
  433. NSMutableArray *failHosts = [NSMutableArray array];
  434. for (NSString *host in preHosts) {
  435. int rePreNum = 0;
  436. BOOL isSuccess = NO;
  437. while (rePreNum < dnsRepreHostNum) {
  438. if ([self preFetchHost:host dns:dns error:error]) {
  439. isSuccess = YES;
  440. break;
  441. }
  442. rePreNum += 1;
  443. }
  444. if (!isSuccess) {
  445. [failHosts addObject:host];
  446. }
  447. }
  448. return [failHosts copy];
  449. }
  450. - (BOOL)preFetchHost:(NSString *)preHost dns:(QNInternalDns *)dns error:(NSError **)error {
  451. if (!preHost || preHost.length == 0) {
  452. return NO;
  453. }
  454. NSDictionary *addressDictionary = nil;
  455. @synchronized (self) {
  456. addressDictionary = [self.addressDictionary copy];
  457. }
  458. NSArray<QNDnsNetworkAddress *>* preAddressList = addressDictionary[preHost];
  459. if (preAddressList && ![preAddressList.firstObject needRefresh]) {
  460. return YES;
  461. }
  462. NSArray <id <QNIDnsNetworkAddress> > * addressList = [dns query:preHost error:error];
  463. if (addressList && addressList.count > 0) {
  464. NSMutableArray *addressListP = [NSMutableArray array];
  465. for (id <QNIDnsNetworkAddress>inetAddress in addressList) {
  466. QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:inetAddress];
  467. if (address) {
  468. address.hostValue = preHost;
  469. if (!address.ttlValue) {
  470. address.ttlValue = @(kQNDefaultDnsCacheTime);
  471. }
  472. if (!address.timestampValue) {
  473. address.timestampValue = @([[NSDate date] timeIntervalSince1970]);
  474. }
  475. [addressListP addObject:address];
  476. }
  477. }
  478. addressListP = [addressListP copy];
  479. @synchronized (self) {
  480. self.addressDictionary[preHost] = addressListP;
  481. }
  482. return YES;
  483. } else {
  484. return NO;
  485. }
  486. }
  487. //MARK: -- 加载和存储缓存信息
  488. - (BOOL)recoverDnsCache:(NSDictionary *)dataDic{
  489. if (dataDic == nil) {
  490. return NO;
  491. }
  492. NSMutableDictionary *records = [NSMutableDictionary dictionary];
  493. for (NSString *key in dataDic.allKeys) {
  494. NSArray *ips = dataDic[key];
  495. if ([ips isKindOfClass:[NSArray class]]) {
  496. NSMutableArray <QNDnsNetworkAddress *> * addressList = [NSMutableArray array];
  497. for (NSDictionary *ipInfo in ips) {
  498. if ([ipInfo isKindOfClass:[NSDictionary class]]) {
  499. QNDnsNetworkAddress *address = [QNDnsNetworkAddress inetAddress:ipInfo];
  500. if (address) {
  501. [addressList addObject:address];
  502. }
  503. }
  504. }
  505. if (addressList.count > 0) {
  506. records[key] = [addressList copy];
  507. }
  508. }
  509. }
  510. @synchronized (self) {
  511. [self.addressDictionary setValuesForKeysWithDictionary:records];
  512. }
  513. return NO;
  514. }
  515. - (BOOL)recorderDnsCache{
  516. NSTimeInterval currentTime = [QNUtils currentTimestamp];
  517. NSString *localIp = [QNIP local];
  518. if (localIp == nil || localIp.length == 0) {
  519. return NO;
  520. }
  521. NSError *error;
  522. id <QNRecorderDelegate> recorder = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir
  523. error:&error];
  524. if (error) {
  525. return NO;
  526. }
  527. NSDictionary *addressDictionary = nil;
  528. @synchronized (self) {
  529. addressDictionary = [self.addressDictionary copy];
  530. }
  531. NSMutableDictionary *addressInfo = [NSMutableDictionary dictionary];
  532. for (NSString *key in addressDictionary.allKeys) {
  533. NSArray *addressModelList = addressDictionary[key];
  534. NSMutableArray * addressDicList = [NSMutableArray array];
  535. for (QNDnsNetworkAddress *ipInfo in addressModelList) {
  536. NSDictionary *addressDic = [ipInfo toDictionary];
  537. if (addressDic) {
  538. [addressDicList addObject:addressDic];
  539. }
  540. }
  541. if (addressDicList.count > 0) {
  542. addressInfo[key] = addressDicList;
  543. }
  544. }
  545. QNDnsCacheInfo *cacheInfo = [QNDnsCacheInfo dnsCacheInfo:[NSString stringWithFormat:@"%.0lf",currentTime]
  546. localIp:localIp
  547. info:addressInfo];
  548. NSData *cacheData = [cacheInfo jsonData];
  549. if (!cacheData) {
  550. return NO;
  551. }
  552. [self setDnsCacheInfo:cacheInfo];
  553. [recorder set:localIp data:cacheData];
  554. return true;
  555. }
  556. - (void)clearDnsCacheIfNeeded{
  557. NSString *localIp = [QNIP local];
  558. if (localIp == nil || (self.dnsCacheInfo && ![localIp isEqualToString:self.dnsCacheInfo.localIp])) {
  559. [self clearDnsMemoryCache];
  560. }
  561. }
  562. - (void)clearDnsMemoryCache {
  563. @synchronized (self) {
  564. [self.addressDictionary removeAllObjects];
  565. }
  566. }
  567. - (void)clearDnsDiskCache:(NSError **)error {
  568. [self.diskCache clearCache:error];
  569. }
  570. //MARK: -- 获取预取hosts
  571. - (NSArray <NSString *> *)getLocalPreHost{
  572. NSMutableArray *localHosts = [NSMutableArray array];
  573. [localHosts addObject:kQNUpLogHost];
  574. return [localHosts copy];
  575. }
  576. - (NSArray <NSString *> *)getCurrentZoneHosts:(QNZone *)currentZone
  577. token:(QNUpToken *)token{
  578. if (!currentZone || !token || !token.token) {
  579. return nil;
  580. }
  581. [currentZone preQuery:token on:^(int code, QNResponseInfo *responseInfo, QNUploadRegionRequestMetrics *metrics) {
  582. dispatch_semaphore_signal(self.semaphore);
  583. }];
  584. dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
  585. QNZonesInfo *autoZonesInfo = [currentZone getZonesInfoWithToken:token];
  586. NSMutableArray *autoHosts = [NSMutableArray array];
  587. NSArray *zoneInfoList = autoZonesInfo.zonesInfo;
  588. for (QNZoneInfo *info in zoneInfoList) {
  589. if (info.allHosts) {
  590. [autoHosts addObjectsFromArray:info.allHosts];
  591. }
  592. }
  593. return [autoHosts copy];
  594. }
  595. //MARK: --
  596. - (BOOL)isDnsOpen{
  597. return [kQNGlobalConfiguration isDnsOpen];
  598. }
  599. - (QNDnsCacheInfo *)dnsCacheInfo{
  600. if (_dnsCacheInfo == nil) {
  601. _dnsCacheInfo = [[QNDnsCacheInfo alloc] init];
  602. }
  603. return _dnsCacheInfo;
  604. }
  605. - (NSMutableDictionary<NSString *,NSArray<QNDnsNetworkAddress *> *> *)addressDictionary{
  606. if (_addressDictionary == nil) {
  607. _addressDictionary = [NSMutableDictionary dictionary];
  608. }
  609. return _addressDictionary;
  610. }
  611. - (dispatch_semaphore_t)semaphore{
  612. if (_getAutoZoneSemaphore == NULL) {
  613. _getAutoZoneSemaphore = dispatch_semaphore_create(0);
  614. }
  615. return _getAutoZoneSemaphore;
  616. }
  617. - (QNDnsCacheFile *)diskCache {
  618. if (!_diskCache) {
  619. NSError *error;
  620. QNDnsCacheFile *cache = [QNDnsCacheFile dnsCacheFile:kQNGlobalConfiguration.dnsCacheDir error:&error];
  621. if (!error) {
  622. _diskCache = cache;
  623. }
  624. }
  625. return _diskCache;
  626. }
  627. - (QNInternalDns *)customDns {
  628. if (_customDns == nil && kQNGlobalConfiguration.dns) {
  629. _customDns = [QNInternalDns dnsWithDns:kQNGlobalConfiguration.dns];
  630. }
  631. return _customDns;
  632. }
  633. - (QNInternalDns *)systemDns {
  634. if (_systemDns == nil) {
  635. _systemDns = [QNInternalDns dnsWithResolver:[[QNResolver alloc] initWithAddress:nil timeout:self.dnsPrefetchTimeout]];
  636. }
  637. return _systemDns;
  638. }
  639. - (NSMutableSet *)prefetchHosts {
  640. if (!_prefetchHosts) {
  641. _prefetchHosts = [NSMutableSet set];
  642. }
  643. return _prefetchHosts;
  644. }
  645. @end
  646. //MARK: -- DNS 事务
  647. @implementation QNTransactionManager(Dns)
  648. #define kQNLoadLocalDnsTransactionName @"QNLoadLocalDnsTransaction"
  649. #define kQNDnsCheckAndPrefetchTransactionName @"QNDnsCheckAndPrefetchTransactionName"
  650. - (void)addDnsLocalLoadTransaction{
  651. if ([kQNDnsPrefetch isDnsOpen] == NO) {
  652. return;
  653. }
  654. static dispatch_once_t onceToken;
  655. dispatch_once(&onceToken, ^{
  656. QNTransaction *transaction = [QNTransaction transaction:kQNLoadLocalDnsTransactionName after:0 action:^{
  657. [kQNDnsPrefetch recoverCache];
  658. [kQNDnsPrefetch localFetch];
  659. }];
  660. [[QNTransactionManager shared] addTransaction:transaction];
  661. [self setDnsCheckWhetherCachedValidTransactionAction];
  662. });
  663. }
  664. - (BOOL)addDnsCheckAndPrefetchTransaction:(QNZone *)currentZone token:(QNUpToken *)token{
  665. if (!token) {
  666. return NO;
  667. }
  668. if ([kQNDnsPrefetch isDnsOpen] == NO) {
  669. return NO;
  670. }
  671. BOOL ret = NO;
  672. @synchronized (kQNDnsPrefetch) {
  673. QNTransactionManager *transactionManager = [QNTransactionManager shared];
  674. if (![transactionManager existTransactionsForName:token.token]) {
  675. QNTransaction *transaction = [QNTransaction transaction:token.token after:0 action:^{
  676. [kQNDnsPrefetch checkAndPrefetchDnsIfNeed:currentZone token:token];
  677. }];
  678. [transactionManager addTransaction:transaction];
  679. ret = YES;
  680. }
  681. }
  682. return ret;
  683. }
  684. - (void)setDnsCheckWhetherCachedValidTransactionAction{
  685. if ([kQNDnsPrefetch isDnsOpen] == NO) {
  686. return;
  687. }
  688. @synchronized (kQNDnsPrefetch) {
  689. QNTransactionManager *transactionManager = [QNTransactionManager shared];
  690. QNTransaction *transaction = [transactionManager transactionsForName:kQNDnsCheckAndPrefetchTransactionName].firstObject;
  691. if (!transaction) {
  692. QNTransaction *transaction = [QNTransaction timeTransaction:kQNDnsCheckAndPrefetchTransactionName
  693. after:10
  694. interval:120
  695. action:^{
  696. [kQNDnsPrefetch checkWhetherCachedDnsValid];
  697. }];
  698. [transactionManager addTransaction:transaction];
  699. } else {
  700. [transactionManager performTransaction:transaction];
  701. }
  702. }
  703. }
  704. @end
  705. BOOL kQNIsDnsSourceDoh(NSString * _Nullable source) {
  706. return [source containsString:kQNDnsSourceDoh];
  707. }
  708. BOOL kQNIsDnsSourceUdp(NSString * _Nullable source) {
  709. return [source containsString:kQNDnsSourceUdp];
  710. }
  711. BOOL kQNIsDnsSourceDnsPod(NSString * _Nullable source) {
  712. return [source containsString:kQNDnsSourceDnspod];
  713. }
  714. BOOL kQNIsDnsSourceSystem(NSString * _Nullable source) {
  715. return [source containsString:kQNDnsSourceSystem];
  716. }
  717. BOOL kQNIsDnsSourceCustom(NSString * _Nullable source) {
  718. return [source containsString:kQNDnsSourceCustom];
  719. }