解决了语音上传到问题,接下来要解决下载播放问题
This commit is contained in:
8
Podfile
Normal file
8
Podfile
Normal file
@@ -0,0 +1,8 @@
|
||||
source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
|
||||
|
||||
platform :ios, '9.0'
|
||||
|
||||
target 'msext' do
|
||||
# 添加七牛云SDK
|
||||
pod 'Qiniu', '~> 8.0'
|
||||
end
|
||||
20
Podfile.lock
Normal file
20
Podfile.lock
Normal file
@@ -0,0 +1,20 @@
|
||||
PODS:
|
||||
- HappyDNS (1.0.4)
|
||||
- Qiniu (8.8.1):
|
||||
- HappyDNS (~> 1.0.4)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Qiniu (~> 8.0)
|
||||
|
||||
SPEC REPOS:
|
||||
https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git:
|
||||
- HappyDNS
|
||||
- Qiniu
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
HappyDNS: aefbd28cdcda93cffac64013dfe3342a2f87ed0a
|
||||
Qiniu: 37131e52fdf43fe70da0c89dd0df3c9ce25bb74b
|
||||
|
||||
PODFILE CHECKSUM: 4aa3a53aaead366c96efe2b5f93ec0e4c4468bc0
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
36
Pods/HappyDNS/HappyDNS/Common/QNDnsError.h
generated
Normal file
36
Pods/HappyDNS/HappyDNS/Common/QNDnsError.h
generated
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// QNDnsError.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern const int kQNDomainHijackingCode;
|
||||
extern const int kQNDomainNotOwnCode;
|
||||
extern const int kQNDomainSeverError;
|
||||
|
||||
extern const int kQNDnsMethodErrorCode;
|
||||
extern const int kQNDnsInvalidParamCode;
|
||||
extern const int kQNDnsResponseBadTypeCode;
|
||||
extern const int kQNDnsResponseBadClassCode;
|
||||
extern const int kQNDnsResponseFormatCode;
|
||||
|
||||
#define kQNDnsErrorDomain @"qiniu.dns"
|
||||
|
||||
@interface QNDnsError : NSObject
|
||||
|
||||
+ (NSError *)error:(int)code desc:(NSString *)desc;
|
||||
|
||||
@end
|
||||
|
||||
#define kQNDnsMethodError(description) [QNDnsError error:kQNDnsMethodErrorCode desc:description]
|
||||
#define kQNDnsInvalidParamError(description) [QNDnsError error:kQNDnsInvalidParamCode desc:description]
|
||||
#define kQNDnsResponseBadTypeError(description) [QNDnsError error:kQNDnsResponseBadTypeCode desc:description]
|
||||
#define kQNDnsResponseBadClassError(description) [QNDnsError error:kQNDnsResponseBadClassCode desc:description]
|
||||
#define kQNDnsResponseFormatError(description) [QNDnsError error:kQNDnsResponseFormatCode desc:description]
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
27
Pods/HappyDNS/HappyDNS/Common/QNDnsError.m
generated
Normal file
27
Pods/HappyDNS/HappyDNS/Common/QNDnsError.m
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// QNDnsError.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import "QNDnsError.h"
|
||||
|
||||
const int kQNDomainHijackingCode = -7001;
|
||||
const int kQNDomainNotOwnCode = -7002;
|
||||
const int kQNDomainSeverError = -7003;
|
||||
|
||||
const int kQNDnsMethodErrorCode = -7010;
|
||||
|
||||
const int kQNDnsInvalidParamCode = -7021;
|
||||
const int kQNDnsResponseBadTypeCode = -7022;
|
||||
const int kQNDnsResponseBadClassCode = -7023;
|
||||
const int kQNDnsResponseFormatCode = -7024;
|
||||
|
||||
@implementation QNDnsError
|
||||
|
||||
+ (NSError *)error:(int)code desc:(NSString *)desc {
|
||||
return [NSError errorWithDomain:kQNDnsErrorDomain code:code userInfo:@{@"user_info" : desc ?: @"nil"}];
|
||||
}
|
||||
|
||||
@end
|
||||
174
Pods/HappyDNS/HappyDNS/Common/QNDnsManager.h
generated
Normal file
174
Pods/HappyDNS/HappyDNS/Common/QNDnsManager.h
generated
Normal file
@@ -0,0 +1,174 @@
|
||||
//
|
||||
// QNDnsManager.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
|
||||
@class QNNetworkInfo;
|
||||
@class QNDomain;
|
||||
|
||||
/**
|
||||
* getaddrinfo 回调上层的函数
|
||||
*
|
||||
* @param host 请求的域名
|
||||
* @return ip 列表
|
||||
*/
|
||||
typedef NSArray<NSString *> * (^QNGetAddrInfoCallback)(NSString *host);
|
||||
|
||||
/**
|
||||
* ip status 回调上层的函数
|
||||
*
|
||||
* @param ip 请求的IP
|
||||
* @param code 错误码
|
||||
* @param ms 消耗时间
|
||||
*/
|
||||
typedef void (^QNIpStatusCallback)(NSString *ip, int code, int ms);
|
||||
|
||||
/**
|
||||
* 外部 Record 排序接口
|
||||
*/
|
||||
@protocol QNRecordSorter <NSObject>
|
||||
|
||||
/**
|
||||
* 排序方法
|
||||
*
|
||||
* @param ips 传入的IP列表
|
||||
*
|
||||
* @return 返回排序好的IP 列表
|
||||
*/
|
||||
- (NSArray<QNRecord *> *)sort:(NSArray<QNRecord *> *)ips;
|
||||
@end
|
||||
|
||||
/**
|
||||
* DNS请求客户端,集成了cache管理
|
||||
*/
|
||||
@interface QNDnsManager : NSObject
|
||||
|
||||
/// 查询失败时抛出错误信息回调
|
||||
@property(nonatomic, copy)void(^queryErrorHandler)(NSError *error, NSString *host);
|
||||
|
||||
/**
|
||||
* 解析域名
|
||||
*
|
||||
* @param domain 域名
|
||||
*
|
||||
* @return QNRecord列表 QNRecord.value即为host
|
||||
*/
|
||||
- (NSArray <QNRecord *> *)queryRecords:(NSString *)domain;
|
||||
|
||||
/**
|
||||
* 解析域名,使用Domain对象进行详细约定
|
||||
*
|
||||
* @param domain 配置了一些domain 参数的 domain 对象
|
||||
*
|
||||
* @return IP 列表
|
||||
*/
|
||||
- (NSArray <QNRecord *> *)queryRecordsWithDomain:(QNDomain *)domain;
|
||||
|
||||
/**
|
||||
* 通知网络发生变化
|
||||
*
|
||||
* @param netInfo 网络信息
|
||||
*/
|
||||
- (void)onNetworkChange:(QNNetworkInfo *)netInfo;
|
||||
|
||||
/**
|
||||
* Dns client 初始化
|
||||
*
|
||||
* @param resolvers 解析服务器列表
|
||||
* @param netInfo 当前网络信息
|
||||
*
|
||||
* @return DnsManager
|
||||
*/
|
||||
- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo;
|
||||
|
||||
/**
|
||||
* Dns client 初始化
|
||||
*
|
||||
* @param resolvers 解析服务器列表
|
||||
* @param netInfo 当前网络信息
|
||||
* @param sorter 外部排序函数
|
||||
*
|
||||
* @return DnsManager
|
||||
*/
|
||||
- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo sorter:(id<QNRecordSorter>)sorter;
|
||||
|
||||
/**
|
||||
* 内置 Hosts 解析
|
||||
*
|
||||
* @param domain 域名
|
||||
* @param ipv4 对应IPv4 ip
|
||||
*
|
||||
* @return 当前Dnsmanager, 为了链式调用
|
||||
*/
|
||||
- (instancetype)putHosts:(NSString *)domain ipv4:(NSString *)ipv4;
|
||||
|
||||
/**
|
||||
* 内置 Hosts 解析
|
||||
*
|
||||
* @param domain 域名
|
||||
* @param ip 对应IP
|
||||
* @param type ip 类别,kQNTypeA / kQNTypeAAAA
|
||||
* @param provider 网络运营商
|
||||
*
|
||||
* @return 当前Dnsmanager, 为了链式调用
|
||||
*/
|
||||
- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip type:(int)type provider:(int)provider;
|
||||
|
||||
/**
|
||||
* 内置 Hosts 解析
|
||||
*
|
||||
* @param domain 域名
|
||||
* @param record 对应 record 记录
|
||||
* @param provider 网络运营商
|
||||
*
|
||||
* @return 当前Dnsmanager, 为了链式调用
|
||||
*/
|
||||
- (instancetype)putHosts:(NSString *)domain record:(QNRecord *)record provider:(int)provider;
|
||||
|
||||
/**
|
||||
* 设置底层 getaddrinfo 使用的回调
|
||||
*
|
||||
* @param block 回调的代码块
|
||||
*/
|
||||
+ (void)setGetAddrInfoBlock:(QNGetAddrInfoCallback)block;
|
||||
|
||||
/**
|
||||
* 设置底层 getaddrinfo 回调使用的dnsmanager
|
||||
*
|
||||
* @param dns 回调用的dnsmanager
|
||||
*/
|
||||
+ (void)setDnsManagerForGetAddrInfo:(QNDnsManager *)dns;
|
||||
|
||||
/**
|
||||
* 设置底层 业务统计 如connect 回调使用的Callback
|
||||
*
|
||||
* @param block 回调返回该IP状态
|
||||
*/
|
||||
+ (void)setIpStatusCallback:(QNIpStatusCallback)block;
|
||||
|
||||
/**
|
||||
* 根据时区判断是否要设置httpDns
|
||||
*/
|
||||
+ (BOOL)needHttpDns;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* DnsManager 的 URL 辅助类
|
||||
*/
|
||||
@interface QNDnsManager (NSURL)
|
||||
|
||||
/**
|
||||
* 使用URL 进行请求
|
||||
*
|
||||
* @param url 请求的Url
|
||||
*
|
||||
* @return 返回IP 替换过的url
|
||||
*/
|
||||
- (NSURL *)queryAndReplaceWithIP:(NSURL *)url;
|
||||
@end
|
||||
322
Pods/HappyDNS/HappyDNS/Common/QNDnsManager.m
generated
Normal file
322
Pods/HappyDNS/HappyDNS/Common/QNDnsManager.m
generated
Normal file
@@ -0,0 +1,322 @@
|
||||
//
|
||||
// QNDnsManager.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNDnsManager.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNHosts.h"
|
||||
#import "QNIP.h"
|
||||
#import "QNLruCache.h"
|
||||
#import "QNNetworkInfo.h"
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolverDelegate.h"
|
||||
|
||||
#include "QNGetAddrInfo.h"
|
||||
|
||||
@interface QNDnsManager ()
|
||||
|
||||
@property (nonatomic, strong) QNLruCache *cache;
|
||||
@property (atomic) QNNetworkInfo *curNetwork;
|
||||
@property (nonatomic) NSArray *resolvers;
|
||||
@property (atomic) UInt32 resolverStatus;
|
||||
@property (nonatomic, strong) QNHosts *hosts;
|
||||
@property (nonatomic, strong) id<QNRecordSorter> sorter;
|
||||
@end
|
||||
|
||||
//static inline BOOL bits_isSet(UInt32 v, int index) {
|
||||
// return (v & (1 << index)) != 0;
|
||||
//}
|
||||
|
||||
static inline UInt32 bits_set(UInt32 v, int bitIndex) {
|
||||
return v |= (1 << bitIndex);
|
||||
}
|
||||
|
||||
static inline UInt32 bits_leadingZeros(UInt32 x) {
|
||||
UInt32 y;
|
||||
int n = 32;
|
||||
y = x >> 16;
|
||||
if (y != 0) {
|
||||
n = n - 16;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 8;
|
||||
if (y != 0) {
|
||||
n = n - 8;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 4;
|
||||
if (y != 0) {
|
||||
n = n - 4;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 2;
|
||||
if (y != 0) {
|
||||
n = n - 2;
|
||||
x = y;
|
||||
}
|
||||
y = x >> 1;
|
||||
if (y != 0) {
|
||||
return n - 2;
|
||||
}
|
||||
return n - x;
|
||||
}
|
||||
|
||||
static NSMutableArray *trimCname(NSArray *records) {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
for (QNRecord *r in records) {
|
||||
if (r.type == kQNTypeA || r.type == kQNTypeAAAA) {
|
||||
[array addObject:r];
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
static NSArray<NSString *> *records2Ips(NSArray<QNRecord *> *records) {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
for (QNRecord *r in records) {
|
||||
if (r.value && r.value.length > 0) {
|
||||
[array addObject:r.value];
|
||||
}
|
||||
}
|
||||
return [array copy];
|
||||
}
|
||||
|
||||
static NSArray<QNRecord *> * filterInvalidRecords(NSArray *records) {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
long long timestamp = [[NSDate date] timeIntervalSince1970];
|
||||
for (QNRecord *r in records) {
|
||||
if (r.value && r.value.length > 0 && ![r expired:timestamp]) {
|
||||
[array addObject:r];
|
||||
}
|
||||
}
|
||||
return [array copy];
|
||||
}
|
||||
|
||||
@interface DummySorter : NSObject <QNRecordSorter>
|
||||
|
||||
@end
|
||||
|
||||
@implementation DummySorter
|
||||
|
||||
//sorted already
|
||||
- (NSArray *)sort:(NSArray *)ips {
|
||||
return ips;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNDnsManager
|
||||
|
||||
- (NSArray <QNRecord *> *)queryRecords:(NSString *)domain {
|
||||
return [self queryRecordsWithDomain:[[QNDomain alloc] init:domain]];
|
||||
}
|
||||
|
||||
- (NSArray <QNRecord *> *)queryRecordsWithDomain:(QNDomain *)domain{
|
||||
if (domain == nil) {
|
||||
return nil;
|
||||
}
|
||||
if ([QNIP mayBeIpV4:domain.domain]) {
|
||||
QNRecord *record = [[QNRecord alloc] init:domain.domain ttl:kQNRecordForeverTTL type:kQNTypeA source:QNRecordSourceUnknown];
|
||||
return [NSArray arrayWithObject:record];
|
||||
}
|
||||
NSArray<QNRecord *> *records = [self queryInternalWithDomain:domain];
|
||||
return [_sorter sort:records];
|
||||
}
|
||||
|
||||
- (NSArray <QNRecord *> *)queryInternalWithDomain:(QNDomain *)domain {
|
||||
if (domain.hostsFirst) {
|
||||
NSArray <QNRecord *> *result = [_hosts query:domain networkInfo:_curNetwork];
|
||||
result = filterInvalidRecords(result);
|
||||
if (result.count > 0) {
|
||||
return [result copy];
|
||||
}
|
||||
}
|
||||
|
||||
if ([_curNetwork isEqualToInfo:[QNNetworkInfo normal]] && [QNNetworkInfo isNetworkChanged]) {
|
||||
@synchronized(_cache) {
|
||||
[_cache removeAllObjects];
|
||||
}
|
||||
_resolverStatus = 0;
|
||||
} else {
|
||||
@synchronized(_cache) {
|
||||
NSArray *result = [_cache objectForKey:domain.domain];
|
||||
result = filterInvalidRecords(result);
|
||||
if (result.count > 0) {
|
||||
return [result copy];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *records = nil;
|
||||
NSError *error = nil;
|
||||
int firstOk = 32 - bits_leadingZeros(_resolverStatus);
|
||||
for (int i = 0; i < _resolvers.count; i++) {
|
||||
int pos = (firstOk + i) % _resolvers.count;
|
||||
id<QNResolverDelegate> resolver = [_resolvers objectAtIndex:pos];
|
||||
QNNetworkInfo *previousNetwork = _curNetwork;
|
||||
NSString *previousIp = [QNNetworkInfo getIp];
|
||||
records = [resolver query:domain networkInfo:previousNetwork error:&error];
|
||||
if (error != nil) {
|
||||
NSError *tmp = error;
|
||||
error = nil;
|
||||
if (tmp.code == kQNDomainNotOwnCode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self.queryErrorHandler) {
|
||||
self.queryErrorHandler(error, domain.domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (records == nil || records.count == 0) {
|
||||
if (_curNetwork == previousNetwork && [previousIp isEqualToString:[QNNetworkInfo getIp]]) {
|
||||
_resolverStatus = bits_set(_resolverStatus, pos);
|
||||
}
|
||||
} else {
|
||||
NSMutableArray *result = trimCname(records);
|
||||
if (_curNetwork == previousNetwork && [previousIp isEqualToString:[QNNetworkInfo getIp]]) {
|
||||
@synchronized(_cache) {
|
||||
[_cache setObject:[result copy] forKey:domain.domain];
|
||||
}
|
||||
}
|
||||
return [result copy];
|
||||
}
|
||||
}
|
||||
|
||||
if (!domain.hostsFirst) {
|
||||
return [_hosts query:domain networkInfo:_curNetwork];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo {
|
||||
return [self init:resolvers networkInfo:netInfo sorter:nil];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSArray *)resolvers networkInfo:(QNNetworkInfo *)netInfo sorter:(id<QNRecordSorter>)sorter {
|
||||
if (self = [super init]) {
|
||||
_cache = [[QNLruCache alloc] init:1024];
|
||||
_curNetwork = netInfo;
|
||||
_resolvers = [[NSArray alloc] initWithArray:resolvers];
|
||||
_hosts = [[QNHosts alloc] init];
|
||||
if (sorter == nil) {
|
||||
_sorter = [[DummySorter alloc] init];
|
||||
} else {
|
||||
_sorter = sorter;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onNetworkChange:(QNNetworkInfo *)netInfo {
|
||||
@synchronized(_cache) {
|
||||
[_cache removeAllObjects];
|
||||
}
|
||||
_curNetwork = netInfo;
|
||||
}
|
||||
|
||||
- (instancetype)putHosts:(NSString *)domain ipv4:(NSString *)ipv4 {
|
||||
return [self putHosts:domain ip:ipv4 type:kQNTypeA provider:kQNISP_GENERAL];
|
||||
}
|
||||
|
||||
- (instancetype)putHosts:(NSString *)domain ip:(NSString *)ip type:(int)type provider:(int)provider {
|
||||
return [self putHosts:domain record:[[QNRecord alloc] init:ip ttl:kQNRecordForeverTTL type:type source:QNRecordSourceCustom] provider:provider];
|
||||
}
|
||||
|
||||
- (instancetype)putHosts:(NSString *)domain record:(QNRecord *)record provider:(int)provider {
|
||||
QNRecord *recordNew = [[QNRecord alloc] init:record.value ttl:record.ttl type:record.type timeStamp:record.timeStamp server:record.server source:QNRecordSourceCustom];
|
||||
[_hosts put:domain record:recordNew provider:provider];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSURL *)queryAndReplaceWithIP:(NSURL *)url {
|
||||
NSURLComponents *urlComponents = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:YES];
|
||||
if (!urlComponents) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *host = urlComponents.host;
|
||||
NSArray<QNRecord *> *records = [self queryRecords:host];
|
||||
|
||||
NSURL *URL = nil;
|
||||
if (records && records.firstObject) {
|
||||
urlComponents.host = [QNIP ipHost:records.firstObject.value];
|
||||
}
|
||||
|
||||
URL = urlComponents.URL;
|
||||
return URL;
|
||||
}
|
||||
|
||||
static QNGetAddrInfoCallback getAddrInfoCallback = nil;
|
||||
static qn_ips_ret *dns_callback_internal(const char *host) {
|
||||
if (getAddrInfoCallback == nil) {
|
||||
return NULL;
|
||||
}
|
||||
NSString *s = [[NSString alloc] initWithUTF8String:host];
|
||||
if (s == nil) {
|
||||
return NULL;
|
||||
}
|
||||
NSArray *ips = getAddrInfoCallback(s);
|
||||
if (ips == nil) {
|
||||
return NULL;
|
||||
}
|
||||
qn_ips_ret *ret = calloc(sizeof(char *), ips.count + 1);
|
||||
for (int i = 0; i < ips.count; i++) {
|
||||
NSString *ip = ips[i];
|
||||
char *ip2 = strdup([ip cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
ret->ips[i] = ip2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static qn_ips_ret *dns_callback(const char *host) {
|
||||
qn_ips_ret *ret = dns_callback_internal(host);
|
||||
if (ret == NULL) {
|
||||
//only for compatible
|
||||
qn_ips_ret *ret = calloc(sizeof(char *), 2);
|
||||
ret->ips[0] = strdup(host);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QNIpStatusCallback ipStatusCallback = nil;
|
||||
static void ip_status_callback(const char *ip, int code, int time_ms) {
|
||||
if (ipStatusCallback == nil) {
|
||||
return;
|
||||
}
|
||||
NSString *s = [[NSString alloc] initWithUTF8String:ip];
|
||||
if (s == nil) {
|
||||
return;
|
||||
}
|
||||
ipStatusCallback(s, code, time_ms);
|
||||
}
|
||||
|
||||
+ (void)setGetAddrInfoBlock:(QNGetAddrInfoCallback)block {
|
||||
if ([QNIP isIpV6FullySupported] || ![QNIP isV6]) {
|
||||
getAddrInfoCallback = block;
|
||||
qn_set_dns_callback(dns_callback);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)setDnsManagerForGetAddrInfo:(QNDnsManager *)dns {
|
||||
[QNDnsManager setGetAddrInfoBlock:^NSArray<NSString *> *(NSString *host) {
|
||||
NSArray *records = [dns queryRecords:host];
|
||||
return records2Ips(records);
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)setIpStatusCallback:(QNIpStatusCallback)block {
|
||||
ipStatusCallback = block;
|
||||
qn_set_ip_report_callback(ip_status_callback);
|
||||
}
|
||||
|
||||
+ (BOOL)needHttpDns {
|
||||
NSTimeZone *timeZone = [NSTimeZone localTimeZone];
|
||||
NSString *tzName = [timeZone name];
|
||||
return [tzName isEqual:@"Asia/Shanghai"] || [tzName isEqual:@"Asia/Chongqing"] || [tzName isEqual:@"Asia/Harbin"] || [tzName isEqual:@"Asia/Urumqi"];
|
||||
}
|
||||
@end
|
||||
27
Pods/HappyDNS/HappyDNS/Common/QNDomain.h
generated
Normal file
27
Pods/HappyDNS/HappyDNS/Common/QNDomain.h
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// QNDomain.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNDomain : NSObject
|
||||
@property (nonatomic, strong, readonly) NSString *domain;
|
||||
|
||||
// 用来判断劫持
|
||||
@property (nonatomic, readonly) BOOL hasCname;
|
||||
// 用来判断劫持
|
||||
@property (nonatomic, readonly) int maxTtl;
|
||||
|
||||
@property (nonatomic, readonly) BOOL hostsFirst;
|
||||
|
||||
- (instancetype)init:(NSString *)domain;
|
||||
|
||||
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname;
|
||||
|
||||
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname maxTtl:(int)maxTtl;
|
||||
|
||||
@end
|
||||
30
Pods/HappyDNS/HappyDNS/Common/QNDomain.m
generated
Normal file
30
Pods/HappyDNS/HappyDNS/Common/QNDomain.m
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// QNDomain.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNDomain.h"
|
||||
|
||||
@implementation QNDomain
|
||||
- (instancetype)init:(NSString *)domain {
|
||||
return [self init:domain hostsFirst:NO hasCname:NO maxTtl:0];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname {
|
||||
return [self init:domain hostsFirst:hostsFirst hasCname:hasCname maxTtl:0];
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSString *)domain hostsFirst:(BOOL)hostsFirst hasCname:(BOOL)hasCname maxTtl:(int)maxTtl {
|
||||
if (self = [super init]) {
|
||||
_domain = domain;
|
||||
_hasCname = hasCname;
|
||||
_maxTtl = maxTtl;
|
||||
_hostsFirst = hostsFirst;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
23
Pods/HappyDNS/HappyDNS/Common/QNLruCache.h
generated
Normal file
23
Pods/HappyDNS/HappyDNS/Common/QNLruCache.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// QNLruCache.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/7/5.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNLruCache : NSObject
|
||||
|
||||
- (instancetype)init:(NSUInteger)limit;
|
||||
|
||||
- (void)removeAllObjects;
|
||||
|
||||
- (void)removeObjectForKey:(NSString *)key;
|
||||
|
||||
- (id)objectForKey:(NSString *)key;
|
||||
|
||||
- (void)setObject:(id)obj forKey:(NSString *)key;
|
||||
|
||||
@end
|
||||
90
Pods/HappyDNS/HappyDNS/Common/QNLruCache.m
generated
Normal file
90
Pods/HappyDNS/HappyDNS/Common/QNLruCache.m
generated
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// QNLruCache.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/7/5.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNLruCache.h"
|
||||
|
||||
@interface QNLruCache ()
|
||||
|
||||
@property (nonatomic, readonly) NSUInteger limit;
|
||||
|
||||
@property (nonatomic, readonly) NSMutableDictionary* cache;
|
||||
|
||||
@property (nonatomic, readonly) NSMutableArray* list;
|
||||
|
||||
@end
|
||||
|
||||
@interface _QNElement : NSObject
|
||||
@property (nonatomic, readonly, strong) NSString* key;
|
||||
@property (nonatomic, strong) id obj;
|
||||
- (instancetype)initObject:(id)obj forKey:(NSString*)key;
|
||||
@end
|
||||
|
||||
@implementation _QNElement
|
||||
|
||||
- (instancetype)initObject:(id)obj forKey:(NSString*)key {
|
||||
if (self = [super init]) {
|
||||
_key = key;
|
||||
_obj = obj;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNLruCache
|
||||
|
||||
- (instancetype)init:(NSUInteger)limit {
|
||||
if (self = [super init]) {
|
||||
_limit = limit;
|
||||
_cache = [NSMutableDictionary new];
|
||||
_list = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)removeAllObjects {
|
||||
[_cache removeAllObjects];
|
||||
[_list removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)removeObjectForKey:(NSString*)key {
|
||||
_QNElement* obj = [_cache objectForKey:key];
|
||||
if (obj == nil) {
|
||||
return;
|
||||
}
|
||||
[_cache removeObjectForKey:key];
|
||||
[_list removeObjectIdenticalTo:obj];
|
||||
}
|
||||
|
||||
- (id)objectForKey:(NSString*)key {
|
||||
_QNElement* obj = [_cache objectForKey:key];
|
||||
if (obj != nil) {
|
||||
[_list removeObjectIdenticalTo:obj];
|
||||
[_list insertObject:obj atIndex:0];
|
||||
}
|
||||
return obj.obj;
|
||||
}
|
||||
|
||||
- (void)setObject:(id)obj forKey:(NSString*)key {
|
||||
_QNElement* old = [_cache objectForKey:key];
|
||||
if (old) {
|
||||
old.obj = obj;
|
||||
[_list removeObjectIdenticalTo:old];
|
||||
[_list insertObject:old atIndex:0];
|
||||
return;
|
||||
} else if (_list.count == _limit) {
|
||||
old = [_list lastObject];
|
||||
[_list removeLastObject];
|
||||
[_cache removeObjectForKey:old.key];
|
||||
}
|
||||
_QNElement* newElement = [[_QNElement alloc] initObject:obj forKey:key];
|
||||
[_cache setObject:newElement forKey:key];
|
||||
[_list insertObject:newElement atIndex:0];
|
||||
}
|
||||
|
||||
@end
|
||||
42
Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.h
generated
Normal file
42
Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.h
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// QNNetworkInfo.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/25.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern const int kQNNO_NETWORK;
|
||||
extern const int kQNWIFI;
|
||||
extern const int kQNMOBILE;
|
||||
|
||||
extern const int kQNISP_GENERAL;
|
||||
extern const int kQNISP_CTC;
|
||||
extern const int kQNISP_DIANXIN;
|
||||
extern const int kQNISP_CNC;
|
||||
extern const int kQNISP_LIANTONG;
|
||||
extern const int kQNISP_CMCC;
|
||||
extern const int kQNISP_YIDONG;
|
||||
extern const int kQNISP_OTHER;
|
||||
|
||||
@interface QNNetworkInfo : NSObject
|
||||
|
||||
@property (nonatomic, readonly) int networkConnection;
|
||||
@property (nonatomic, readonly) int provider;
|
||||
|
||||
- (instancetype)init:(int)connecton provider:(int)provider;
|
||||
|
||||
- (BOOL)isEqual:(id)other;
|
||||
- (BOOL)isEqualToInfo:(QNNetworkInfo *)info;
|
||||
|
||||
+ (instancetype)noNet;
|
||||
|
||||
+ (instancetype)normal;
|
||||
|
||||
+ (BOOL)isNetworkChanged;
|
||||
|
||||
+ (NSString *)getIp;
|
||||
|
||||
@end
|
||||
86
Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.m
generated
Normal file
86
Pods/HappyDNS/HappyDNS/Common/QNNetworkInfo.m
generated
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// QNNetworkInfo.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/25.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#import "QNIP.h"
|
||||
#import "QNNetworkInfo.h"
|
||||
|
||||
const int kQNNO_NETWORK = -1;
|
||||
const int kQNWIFI = 1;
|
||||
const int kQNMOBILE = 2;
|
||||
|
||||
const int kQNISP_GENERAL = 0;
|
||||
const int kQNISP_CTC = 1;
|
||||
const int kQNISP_DIANXIN = kQNISP_CTC;
|
||||
const int kQNISP_CNC = 2;
|
||||
const int kQNISP_LIANTONG = kQNISP_CNC;
|
||||
const int kQNISP_CMCC = 3;
|
||||
const int kQNISP_YIDONG = kQNISP_CMCC;
|
||||
const int kQNISP_OTHER = 999;
|
||||
|
||||
#define IPLength 64
|
||||
|
||||
static char previousIp[IPLength] = {0};
|
||||
static NSString *lock = @"";
|
||||
|
||||
@implementation QNNetworkInfo
|
||||
|
||||
- (instancetype)init:(int)connecton provider:(int)provider {
|
||||
if (self = [super init]) {
|
||||
_networkConnection = connecton;
|
||||
_provider = provider;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)noNet {
|
||||
return [[QNNetworkInfo alloc] init:kQNNO_NETWORK provider:kQNISP_GENERAL];
|
||||
}
|
||||
|
||||
+ (instancetype)normal {
|
||||
return [[QNNetworkInfo alloc] init:kQNISP_GENERAL provider:kQNISP_GENERAL];
|
||||
}
|
||||
|
||||
- (BOOL)isEqualToInfo:(QNNetworkInfo *)info {
|
||||
if (self == info)
|
||||
return YES;
|
||||
return self.provider == info.provider && self.networkConnection == info.networkConnection;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)other {
|
||||
if (other == self)
|
||||
return YES;
|
||||
if (!other || ![other isKindOfClass:[self class]])
|
||||
return NO;
|
||||
return [self isEqualToInfo:other];
|
||||
}
|
||||
|
||||
+ (BOOL)isNetworkChanged {
|
||||
@synchronized(lock) {
|
||||
char local[IPLength] = {0};
|
||||
int err = qn_localIp(local, sizeof(local));
|
||||
if (err != 0) {
|
||||
return YES;
|
||||
}
|
||||
if (memcmp(previousIp, local, sizeof(local)) != 0) {
|
||||
memcpy(previousIp, local, sizeof(local));
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString *)getIp {
|
||||
return [QNIP local];
|
||||
}
|
||||
@end
|
||||
69
Pods/HappyDNS/HappyDNS/Common/QNRecord.h
generated
Normal file
69
Pods/HappyDNS/HappyDNS/Common/QNRecord.h
generated
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// QNRecord.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* A 记录
|
||||
*/
|
||||
extern const int kQNTypeA;
|
||||
|
||||
/**
|
||||
* AAAA 记录
|
||||
*/
|
||||
extern const int kQNTypeAAAA;
|
||||
|
||||
/**
|
||||
* Cname 记录
|
||||
*/
|
||||
extern const int kQNTypeCname;
|
||||
|
||||
/**
|
||||
* Txt 记录
|
||||
*/
|
||||
extern const int kQNTypeTXT;
|
||||
|
||||
/**
|
||||
* 永久有效的 ttl
|
||||
*/
|
||||
extern const int kQNRecordForeverTTL;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, QNRecordSource) {
|
||||
QNRecordSourceUnknown,
|
||||
QNRecordSourceCustom,
|
||||
QNRecordSourceDnspodEnterprise,
|
||||
QNRecordSourceSystem,
|
||||
QNRecordSourceUdp,
|
||||
QNRecordSourceDoh,
|
||||
};
|
||||
|
||||
|
||||
@interface QNRecord : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *value;
|
||||
@property (nonatomic, copy, readonly) NSString *server;
|
||||
@property (nonatomic, readonly) int ttl;
|
||||
@property (nonatomic, readonly) int type;
|
||||
@property (nonatomic, readonly) long long timeStamp;
|
||||
@property (nonatomic, readonly) QNRecordSource source;
|
||||
|
||||
- (instancetype)init:(NSString *)value
|
||||
ttl:(int)ttl
|
||||
type:(int)type
|
||||
source:(QNRecordSource)source;
|
||||
|
||||
- (instancetype)init:(NSString *)value
|
||||
ttl:(int)ttl
|
||||
type:(int)type
|
||||
timeStamp:(long long)timeStamp
|
||||
server:(NSString *)server
|
||||
source:(QNRecordSource)source;
|
||||
|
||||
- (BOOL)expired:(long long)time;
|
||||
|
||||
@end
|
||||
60
Pods/HappyDNS/HappyDNS/Common/QNRecord.m
generated
Normal file
60
Pods/HappyDNS/HappyDNS/Common/QNRecord.m
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// QNRecord.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
|
||||
const int kQNTypeA = 1;
|
||||
const int kQNTypeAAAA = 28;
|
||||
const int kQNTypeCname = 5;
|
||||
const int kQNTypeTXT = 16;
|
||||
const int kQNRecordForeverTTL = -1;
|
||||
|
||||
@implementation QNRecord
|
||||
- (instancetype)init:(NSString *)value
|
||||
ttl:(int)ttl
|
||||
type:(int)type
|
||||
source:(QNRecordSource)source {
|
||||
if (self = [super init]) {
|
||||
_value = value;
|
||||
_type = type;
|
||||
_ttl = ttl;
|
||||
_source = source;
|
||||
_timeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSString *)value
|
||||
ttl:(int)ttl
|
||||
type:(int)type
|
||||
timeStamp:(long long)timeStamp
|
||||
server:(NSString *)server
|
||||
source:(QNRecordSource)source {
|
||||
if (self = [super init]) {
|
||||
_value = value;
|
||||
_type = type;
|
||||
_ttl = ttl;
|
||||
_server = server;
|
||||
_source = source;
|
||||
_timeStamp = timeStamp;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)expired:(long long)time {
|
||||
if (_ttl == kQNRecordForeverTTL) {
|
||||
return false;
|
||||
}
|
||||
return time > _timeStamp + _ttl;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"value:%@, ttl:%d, timestamp:%lld, type:%d server:%@ source:%lu", _value, _ttl, _timeStamp, _type, _server, (unsigned long)_source];
|
||||
}
|
||||
|
||||
@end
|
||||
19
Pods/HappyDNS/HappyDNS/Common/QNResolverDelegate.h
generated
Normal file
19
Pods/HappyDNS/HappyDNS/Common/QNResolverDelegate.h
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// QNResolverDelegate.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNDnsError.h"
|
||||
|
||||
#define QN_DNS_DEFAULT_TIMEOUT 20 //seconds
|
||||
|
||||
@class QNDomain;
|
||||
@class QNNetworkInfo;
|
||||
@protocol QNResolverDelegate <NSObject>
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError **)error;
|
||||
|
||||
@end
|
||||
15
Pods/HappyDNS/HappyDNS/Dns/QNDnsDefine.h
generated
Normal file
15
Pods/HappyDNS/HappyDNS/Dns/QNDnsDefine.h
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// QNDnsDefine.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, QNDnsOpCode) {
|
||||
QNDnsOpCodeQuery = 0, // 标准查询
|
||||
QNDnsOpCodeIQuery = 1, // 反向查询
|
||||
QNDnsOpCodeStatus = 2, // DNS状态请求
|
||||
QNDnsOpCodeUpdate = 5, // DNS域更新请求
|
||||
};
|
||||
41
Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.h
generated
Normal file
41
Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.h
generated
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// QNDnsMessage.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNDnsMessage : NSObject
|
||||
|
||||
/**
|
||||
* 16位的消息ID标示一次正常的交互,该ID由消息请求者设置,消息响应者回复请求时带上该ID。最大:0xFFFF,即:65536
|
||||
*/
|
||||
@property(nonatomic, assign, readonly)int messageId;
|
||||
|
||||
/**
|
||||
* 请求类型,目前有三类值:
|
||||
* 0 QUERY, 标准查询
|
||||
* 1 IQUERY, 反向查询
|
||||
* 2 STATUS, DNS状态请求
|
||||
* 5 UPDATE, DNS域更新请求
|
||||
*/
|
||||
@property(nonatomic, assign, readonly)int opCode;
|
||||
|
||||
/**
|
||||
* 是否递归查询。如果该位被设置为1,则收到请求的域名服务器会递归查询域名,
|
||||
* 注: 该位为1,域名服务器不一定会做递归查询,这取决于域名服务器是否支持递归查询。
|
||||
*/
|
||||
@property(nonatomic, assign, readonly)int rd;
|
||||
|
||||
/**
|
||||
* 在响应消息中清除并设置。表示该DNS域名服务器是否支持递归查询。
|
||||
*/
|
||||
@property(nonatomic, assign, readonly)int ra;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
12
Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.m
generated
Normal file
12
Pods/HappyDNS/HappyDNS/Dns/QNDnsMessage.m
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// QNDnsMessage.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import "QNDnsMessage.h"
|
||||
|
||||
@implementation QNDnsMessage
|
||||
|
||||
@end
|
||||
43
Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.h
generated
Normal file
43
Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.h
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// DnsQuestion.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/16.
|
||||
//
|
||||
|
||||
#import "QNDnsDefine.h"
|
||||
#import "QNDnsMessage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNDnsRequest : QNDnsMessage
|
||||
|
||||
@property(nonatomic, assign, readonly)int recordType;
|
||||
@property(nonatomic, copy, readonly)NSString *host;
|
||||
|
||||
/// 构造函数
|
||||
/// @param messageId 请求 id
|
||||
/// @param recordType 记录类型
|
||||
/// @param host 需要进行 Dns 解析的 host
|
||||
+ (instancetype)request:(int)messageId
|
||||
recordType:(int)recordType
|
||||
host:(NSString *)host;
|
||||
|
||||
/// 构造函数
|
||||
/// @param messageId 请求 id
|
||||
/// @param opCode 请求类型
|
||||
/// @param rd 是否递归查询。如果该位被设置为1,则收到请求的域名服务器会递归查询域名
|
||||
/// 注: 该位为1,域名服务器不一定会做递归查询,这取决于域名服务器是否支持递归查询。
|
||||
/// @param recordType 记录类型
|
||||
/// @param host 需要进行 Dns 解析的 host
|
||||
+ (instancetype)request:(int)messageId
|
||||
opCode:(QNDnsOpCode)opCode
|
||||
rd:(int)rd
|
||||
recordType:(int)recordType
|
||||
host:(NSString *)host;
|
||||
|
||||
- (NSData *)toDnsQuestionData:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
118
Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.m
generated
Normal file
118
Pods/HappyDNS/HappyDNS/Dns/QNDnsRequest.m
generated
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// DnsQuestion.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/16.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
#import "NSData+QNRW.h"
|
||||
#import "QNDnsError.h"
|
||||
#import "QNDnsRequest.h"
|
||||
|
||||
@interface QNDnsRequest()
|
||||
|
||||
@property(nonatomic, assign)int messageId;
|
||||
@property(nonatomic, assign)QNDnsOpCode opCode;
|
||||
@property(nonatomic, assign)int rd;
|
||||
@property(nonatomic, assign)int recordType;
|
||||
@property(nonatomic, copy)NSString *host;
|
||||
|
||||
@end
|
||||
@implementation QNDnsRequest
|
||||
@synthesize messageId;
|
||||
@synthesize opCode;
|
||||
@synthesize rd;
|
||||
|
||||
+ (instancetype)request:(int)messageId
|
||||
recordType:(int)recordType
|
||||
host:(NSString *)host {
|
||||
return [self request:messageId opCode:QNDnsOpCodeQuery rd:1 recordType:recordType host:host];
|
||||
}
|
||||
|
||||
+ (instancetype)request:(int)messageId
|
||||
opCode:(QNDnsOpCode)opCode
|
||||
rd:(int)rd
|
||||
recordType:(int)recordType
|
||||
host:(NSString *)host {
|
||||
QNDnsRequest *request = [[QNDnsRequest alloc] init];
|
||||
request.messageId = messageId;
|
||||
request.opCode = opCode;
|
||||
request.rd = rd;
|
||||
request.recordType = recordType;
|
||||
request.host = host;
|
||||
return request;
|
||||
}
|
||||
|
||||
- (NSData *)toDnsQuestionData:(NSError *__autoreleasing _Nullable *)error {
|
||||
if (self.host == nil || self.host.length == 0) {
|
||||
[self copyError:kQNDnsInvalidParamError(@"host can not empty") toErrorPoint:error];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self.opCode != QNDnsOpCodeQuery &&
|
||||
self.opCode != QNDnsOpCodeIQuery &&
|
||||
self.opCode != QNDnsOpCodeStatus &&
|
||||
self.opCode != QNDnsOpCodeUpdate) {
|
||||
[self copyError:kQNDnsInvalidParamError(@"opCode is not valid") toErrorPoint:error];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self.rd != 0 && self.rd != 1) {
|
||||
[self copyError:kQNDnsInvalidParamError(@"rd is not valid") toErrorPoint:error];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self.recordType != kQNTypeA &&
|
||||
self.recordType != kQNTypeCname &&
|
||||
self.recordType != kQNTypeTXT &&
|
||||
self.recordType != kQNTypeAAAA) {
|
||||
[self copyError:kQNDnsInvalidParamError(@"recordType is not valid") toErrorPoint:error];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
[data qn_appendBigEndianInt16:self.messageId]; // 16 bit id
|
||||
// |00|01|02|03|04|05|06|07|
|
||||
// |QR| OPCODE |AA|TC|RD|
|
||||
[data qn_appendInt8:(self.opCode<<3) + self.rd];
|
||||
// |00|01|02|03|04|05|06|07|
|
||||
// |RA|r1|r2|r3| RCODE |
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:0x01]; // QDCOUNT (number of entries in the question section)
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:0x00]; // ANCOUNT
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:0x00]; // NSCOUNT
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:0x00]; // ARCOUNT
|
||||
|
||||
NSArray *hostParts = [self.host componentsSeparatedByString:@"."];
|
||||
for (NSString *part in hostParts) {
|
||||
if (part.length > 63) {
|
||||
return nil;
|
||||
}
|
||||
[data qn_appendInt8:part.length];
|
||||
[data qn_appendString:part usingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
[data qn_appendInt8:0x00]; /* terminating zero */
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:self.recordType];
|
||||
[data qn_appendInt8:0x00];
|
||||
[data qn_appendInt8:0x01]; /* IN - "the Internet" */
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (void)copyError:(NSError *)error toErrorPoint:(NSError **)errorPoint {
|
||||
if (errorPoint != nil) {
|
||||
*errorPoint = error;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"messageId:%d opcode:%ld rd:%d ra:%d type:%ld", self.messageId, (long)self.opCode, self.rd, self.ra, (long)self.recordType];
|
||||
}
|
||||
|
||||
@end
|
||||
33
Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.h
generated
Normal file
33
Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// QNDnsResolver.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by yangsen on 2021/7/28.
|
||||
// Copyright © 2021 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNDnsDefine.h"
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolverDelegate.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class QNDnsResponse;
|
||||
// 抽象对象,不能直接使用,使用其子类
|
||||
@interface QNDnsResolver : NSObject <QNResolverDelegate>
|
||||
|
||||
@property(nonatomic, assign, readonly)int recordType;
|
||||
@property(nonatomic, assign, readonly)int timeout;
|
||||
@property(nonatomic, copy, readonly)NSArray *servers;
|
||||
|
||||
|
||||
|
||||
// 抽象方法,子类实现
|
||||
- (void)request:(NSString *)server
|
||||
host:(NSString *)host
|
||||
recordType:(int)recordType
|
||||
complete:(void(^)(QNDnsResponse *response, NSError *error))complete;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
129
Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.m
generated
Normal file
129
Pods/HappyDNS/HappyDNS/Dns/QNDnsResolver.m
generated
Normal file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// QNDnsResolver.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by yangsen on 2021/7/28.
|
||||
// Copyright © 2021 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNDnsError.h"
|
||||
#import "QNDnsResponse.h"
|
||||
#import "QNDnsResolver.h"
|
||||
|
||||
@interface QNDnsResolver()
|
||||
|
||||
@property(nonatomic, strong)dispatch_queue_t timerQueue;
|
||||
|
||||
@end
|
||||
@implementation QNDnsResolver
|
||||
+ (dispatch_queue_t)timeoutQueue {
|
||||
static dispatch_once_t onceToken;
|
||||
static dispatch_queue_t timerQueue;
|
||||
dispatch_once(&onceToken, ^{
|
||||
timerQueue = dispatch_queue_create("com.happyDns.timeoutQueue", DISPATCH_QUEUE_CONCURRENT);
|
||||
});
|
||||
return timerQueue;
|
||||
}
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
|
||||
NSError *err = nil;
|
||||
QNDnsResponse *response = [self lookupHost:domain.domain error:&err];
|
||||
if (err != nil) {
|
||||
*error = err;
|
||||
return @[];
|
||||
}
|
||||
|
||||
NSMutableArray *records = [NSMutableArray array];
|
||||
for (QNRecord *record in response.answerArray) {
|
||||
if (record.type == kQNTypeA || record.type == kQNTypeAAAA || record.type == kQNTypeCname) {
|
||||
[records addObject:record];
|
||||
}
|
||||
}
|
||||
return [records copy];
|
||||
}
|
||||
|
||||
- (QNDnsResponse *)lookupHost:(NSString *)host error:(NSError *__autoreleasing _Nullable *)error {
|
||||
|
||||
// 异步转同步
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
__block NSError *errorP = nil;
|
||||
__block QNDnsResponse *dnsResponse = nil;
|
||||
[self request:host recordType:self.recordType complete:^(QNDnsResponse *response, NSError *err) {
|
||||
errorP = err;
|
||||
dnsResponse = response;
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
}];
|
||||
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, self.timeout * NSEC_PER_SEC));
|
||||
|
||||
if (error != NULL) {
|
||||
*error = errorP;
|
||||
}
|
||||
|
||||
return dnsResponse;
|
||||
}
|
||||
|
||||
- (void)request:(NSString *)host
|
||||
recordType:(int)recordType
|
||||
complete:(void(^)(QNDnsResponse *response, NSError *error))complete {
|
||||
if (complete == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.servers == nil || self.servers.count == 0) {
|
||||
complete(nil, kQNDnsInvalidParamError(@"server can not empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
NSLock *locker = [[NSLock alloc] init];
|
||||
__block BOOL hasCallBack = false;
|
||||
__block BOOL completeCount = 0;
|
||||
|
||||
// 超时处理
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), [QNDnsResolver timeoutQueue], ^{
|
||||
BOOL shouldCallBack = false;
|
||||
[locker lock];
|
||||
if (!hasCallBack) {
|
||||
shouldCallBack = true;
|
||||
hasCallBack = true;
|
||||
}
|
||||
[locker unlock];
|
||||
|
||||
if (shouldCallBack) {
|
||||
NSString *error = [NSString stringWithFormat:@"resolver timeout for server:%@ host:%@",[self.servers description], host];
|
||||
complete(nil, kQNDnsInvalidParamError(error));
|
||||
}
|
||||
});
|
||||
|
||||
for (NSString *server in self.servers) {
|
||||
[self request:server host:host recordType:recordType complete:^(QNDnsResponse *response, NSError *error) {
|
||||
BOOL shouldCallBack = false;
|
||||
|
||||
[locker lock];
|
||||
completeCount++;
|
||||
if (completeCount == self.servers.count || (response != nil && response.rCode == 0 && !hasCallBack)) {
|
||||
shouldCallBack = true;
|
||||
hasCallBack = true;
|
||||
}
|
||||
[locker unlock];
|
||||
|
||||
if (shouldCallBack) {
|
||||
complete(response, error);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)request:(NSString *)server
|
||||
host:(NSString *)host
|
||||
recordType:(int)recordType
|
||||
complete:(void(^)(QNDnsResponse *response, NSError *error))complete {
|
||||
if (complete != nil) {
|
||||
complete(nil, kQNDnsMethodError(@"use sub class of QNDnsResolver"));
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
46
Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.h
generated
Normal file
46
Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.h
generated
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// DnsRecord.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/16.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
#import "QNDnsRequest.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNDnsResponse : QNDnsMessage
|
||||
|
||||
@property(nonatomic, assign, readonly)NSInteger timestamp;
|
||||
@property(nonatomic, assign, readonly)QNRecordSource source;
|
||||
@property(nonatomic, copy, readonly)NSString *server;
|
||||
@property(nonatomic, strong, readonly)QNDnsRequest *request;
|
||||
@property(nonatomic, strong, readonly)NSData *recordData;
|
||||
|
||||
|
||||
/**
|
||||
* 响应该消息的域名服务器是该域中的权威域名服务器。因为Answer Section中可能会有很多域名
|
||||
*/
|
||||
@property(nonatomic, assign, readonly)int aa;
|
||||
|
||||
/**
|
||||
* 响应消息的类型:
|
||||
* 0 成功的响应
|
||||
* 1 格式错误--域名服务器无法解析请求,因为请求消息格式错误
|
||||
* 2 服务器错误--域名服务器因为内部错误无法解析该请求
|
||||
* 3 名字错误-- 只在权威域名服务器的响应消息中有效,标示请求中请求的域不存在
|
||||
* 4 Not Implemented--域名服务器不支持请求的类型
|
||||
* 5 Refused -- 域名服务器因为策略的原因拒绝执行请求的操作。例如域名服务器不会为特定的请求者返回查询结果,或者域名服务器不会为特定的请求返回特定的数据
|
||||
*/
|
||||
@property(nonatomic, assign, readonly)int rCode;
|
||||
|
||||
@property(nonatomic, copy, readonly)NSArray <QNRecord *> *answerArray;
|
||||
@property(nonatomic, copy, readonly)NSArray <QNRecord *> *authorityArray;
|
||||
@property(nonatomic, copy, readonly)NSArray <QNRecord *> *additionalArray;
|
||||
|
||||
+ (instancetype)dnsResponse:(NSString *)server source:(QNRecordSource)source request:(QNDnsRequest *)request dnsRecordData:(NSData *)recordData error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
350
Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.m
generated
Normal file
350
Pods/HappyDNS/HappyDNS/Dns/QNDnsResponse.m
generated
Normal file
@@ -0,0 +1,350 @@
|
||||
//
|
||||
// DnsRecord.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/16.
|
||||
//
|
||||
#import "QNRecord.h"
|
||||
#import "QNDnsError.h"
|
||||
#import "NSData+QNRW.h"
|
||||
#import "QNDnsResponse.h"
|
||||
|
||||
|
||||
/// DNS 记录中的名字可能是引用,需要到指定的 index 读取,所以需要跳过的长度不一定是 name 的长度
|
||||
@interface QNDnsRecordName : NSObject
|
||||
|
||||
@property(nonatomic, assign)NSInteger skipLength;
|
||||
@property(nonatomic, copy)NSString *name;
|
||||
|
||||
@end
|
||||
@implementation QNDnsRecordName
|
||||
@end
|
||||
|
||||
|
||||
@interface QNDnsRecordResource : NSObject
|
||||
|
||||
@property(nonatomic, copy)NSString *name;
|
||||
@property(nonatomic, assign)int count;
|
||||
@property(nonatomic, assign)int from;
|
||||
@property(nonatomic, assign)int length;
|
||||
@property(nonatomic, strong)NSMutableArray *records;
|
||||
|
||||
@end
|
||||
@implementation QNDnsRecordResource
|
||||
+ (instancetype)resource:(NSString *)name count:(int)count from:(int)from {
|
||||
QNDnsRecordResource *resource = [[QNDnsRecordResource alloc] init];
|
||||
resource.name = name;
|
||||
resource.count = count;
|
||||
resource.from = from;
|
||||
resource.length = 0;
|
||||
resource.records = [NSMutableArray array];
|
||||
return resource;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface QNDnsResponse()
|
||||
|
||||
@property(nonatomic, assign)NSInteger timestamp;
|
||||
@property(nonatomic, assign)QNRecordSource source;
|
||||
@property(nonatomic, copy)NSString *server;
|
||||
@property(nonatomic, strong)QNDnsRequest *request;
|
||||
@property(nonatomic, strong)NSData *recordData;
|
||||
|
||||
@property(nonatomic, assign)int messageId;
|
||||
@property(nonatomic, assign)QNDnsOpCode opCode;
|
||||
@property(nonatomic, assign)int aa;
|
||||
@property(nonatomic, assign)int ra;
|
||||
@property(nonatomic, assign)int rd;
|
||||
@property(nonatomic, assign)int rCode;
|
||||
|
||||
@property(nonatomic, copy)NSArray <QNRecord *> *answerArray;
|
||||
@property(nonatomic, copy)NSArray <QNRecord *> *authorityArray;
|
||||
@property(nonatomic, copy)NSArray <QNRecord *> *additionalArray;
|
||||
|
||||
@end
|
||||
@implementation QNDnsResponse
|
||||
@synthesize messageId;
|
||||
@synthesize opCode;
|
||||
@synthesize aa;
|
||||
@synthesize ra;
|
||||
@synthesize rd;
|
||||
@synthesize rCode;
|
||||
|
||||
+ (instancetype)dnsResponse:(NSString *)server source:(QNRecordSource)source request:(QNDnsRequest *)request dnsRecordData:(NSData *)recordData error:(NSError *__autoreleasing _Nullable *)error {
|
||||
QNDnsResponse *record = [[QNDnsResponse alloc] init];
|
||||
record.server = server;
|
||||
record.source = source;
|
||||
record.request = request;
|
||||
record.recordData = recordData;
|
||||
record.timestamp = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
NSError *err = nil;
|
||||
[record parse:&err];
|
||||
if (error != nil) {
|
||||
*error = err;
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
- (void)parse:(NSError **)error {
|
||||
|
||||
if (self.recordData.length < 12) {
|
||||
[self copyError:kQNDnsResponseFormatError(@"response data too small") toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
// Header
|
||||
[self parseHeader:error];
|
||||
if (error != nil && *error != nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Question
|
||||
int index = [self parseQuestion:error];
|
||||
if (error != nil && *error != nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Answer
|
||||
QNDnsRecordResource *answer = [QNDnsRecordResource resource:@"answer"
|
||||
count:[self.recordData qn_readBigEndianInt16:6]
|
||||
from:index];
|
||||
[self parseResourceRecord:answer error:error];
|
||||
if (error != nil && *error != nil) {
|
||||
return;
|
||||
}
|
||||
index += answer.length;
|
||||
self.answerArray = [answer.records copy];
|
||||
|
||||
// Authority
|
||||
QNDnsRecordResource *authority = [QNDnsRecordResource resource:@"authority"
|
||||
count:[self.recordData qn_readBigEndianInt16:8]
|
||||
from:index];
|
||||
[self parseResourceRecord:authority error:error];
|
||||
if (error != nil && *error != nil) {
|
||||
return;
|
||||
}
|
||||
index += authority.length;
|
||||
self.authorityArray = [authority.records copy];
|
||||
|
||||
// Additional
|
||||
QNDnsRecordResource *additional = [QNDnsRecordResource resource:@"additional"
|
||||
count:[self.recordData qn_readBigEndianInt16:10]
|
||||
from:index];
|
||||
[self parseResourceRecord:additional error:error];
|
||||
if (error != nil && *error != nil) {
|
||||
return;
|
||||
}
|
||||
self.additionalArray = [additional.records copy];
|
||||
}
|
||||
|
||||
- (void)parseHeader:(NSError **)error {
|
||||
self.messageId = [self.recordData qn_readBigEndianInt16:0];
|
||||
// question id 不匹配
|
||||
if (self.messageId != self.request.messageId) {
|
||||
[self copyError:kQNDnsResponseFormatError(@"question id error") toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
// |00|01|02|03|04|05|06|07|
|
||||
// |QR| OPCODE |AA|TC|RD|
|
||||
int field0 = [self.recordData qn_readInt8:2];
|
||||
int qr = [self.recordData qn_readInt8:2] & 0x80;
|
||||
// 非 dns 响应数据
|
||||
if (qr == 0) {
|
||||
[self copyError:kQNDnsResponseFormatError(@"not a response data") toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
self.opCode = (field0 >> 3) & 0x07;
|
||||
self.aa = (field0 >> 2) & 0x01;
|
||||
self.rd = field0 & 0x01;
|
||||
|
||||
// |00|01|02|03|04|05|06|07|
|
||||
// |RA|r1|r2|r3| RCODE |
|
||||
int field1 = [self.recordData qn_readInt8:3];
|
||||
self.ra = (field1 >> 7) & 0x1;
|
||||
self.rCode = field1 & 0x0F;
|
||||
}
|
||||
|
||||
- (int)parseQuestion:(NSError **)error {
|
||||
int index = 12;
|
||||
int qdCount = [self.recordData qn_readBigEndianInt16:4];
|
||||
while (qdCount) {
|
||||
QNDnsRecordName *recordName = [self getNameFrom:index];
|
||||
if (recordName == nil) {
|
||||
[self copyError:kQNDnsResponseFormatError(@"read Question error") toErrorPoint:error];
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self.recordData.length < (index + recordName.skipLength + 4)) {
|
||||
[self copyError:kQNDnsResponseFormatError(@"read Question error: out of range") toErrorPoint:error];
|
||||
return -1;
|
||||
}
|
||||
|
||||
index += recordName.skipLength + 4;
|
||||
qdCount --;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
- (void)parseResourceRecord:(QNDnsRecordResource *)resource error:(NSError **)error {
|
||||
int index = resource.from;
|
||||
int count = resource.count;
|
||||
while (count) {
|
||||
QNDnsRecordName *recordName = [self getNameFrom:index];
|
||||
if (recordName == nil) {
|
||||
NSString *errorDesc = [NSString stringWithFormat:@"read %@ error", resource.name];
|
||||
[self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
index += recordName.skipLength;
|
||||
if (self.recordData.length < (index + 2)) {
|
||||
NSString *errorDesc = [NSString stringWithFormat:@"read %@ error: out of range", resource.name];
|
||||
[self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
int type = [self.recordData qn_readBigEndianInt16:index];
|
||||
index += 2;
|
||||
|
||||
if (self.recordData.length < (index + 2)) {
|
||||
NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name];
|
||||
[self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
int class = [self.recordData qn_readBigEndianInt16:index];
|
||||
index += 2;
|
||||
|
||||
if (self.recordData.length < (index + 4)) {
|
||||
NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name];
|
||||
[self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
int ttl = [self.recordData qn_readBigEndianInt32:index];
|
||||
index += 4;
|
||||
|
||||
if (self.recordData.length < (index + 2)) {
|
||||
NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name];
|
||||
[self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
int rdLength = [self.recordData qn_readBigEndianInt16:index];
|
||||
index += 2;
|
||||
if (self.recordData.length < (index + rdLength)) {
|
||||
NSString *errorDesc = [NSString stringWithFormat:@"%@ read Answer error: out of range", resource.name];
|
||||
[self copyError:kQNDnsResponseFormatError(errorDesc) toErrorPoint:error];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *value = [self readData:type range:NSMakeRange(index, rdLength)];
|
||||
|
||||
if (class == 0x01 && (type == kQNTypeCname || type == self.request.recordType)) {
|
||||
QNRecord *record = [[QNRecord alloc] init:[value copy] ttl:ttl type:type timeStamp:self.timestamp server:self.server source:self.source];
|
||||
[resource.records addObject:record];
|
||||
}
|
||||
|
||||
index += rdLength;
|
||||
count --;
|
||||
}
|
||||
resource.length = index - resource.from;
|
||||
}
|
||||
|
||||
- (QNDnsRecordName *)getNameFrom:(NSInteger)fromIndex {
|
||||
|
||||
NSInteger partLength = 0;
|
||||
NSInteger index = fromIndex;
|
||||
NSMutableString *name = [NSMutableString string];
|
||||
QNDnsRecordName *recordName = [[QNDnsRecordName alloc] init];
|
||||
|
||||
int maxLoop = 128;
|
||||
do {
|
||||
if (index >= self.recordData.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
partLength = [self.recordData qn_readInt8:index];
|
||||
if ((partLength & 0xc0) == 0xc0) {
|
||||
// name pointer
|
||||
if((index + 1) >= self.recordData.length) {
|
||||
return nil;
|
||||
}
|
||||
if (recordName.skipLength < 1) {
|
||||
recordName.skipLength = index + 2 - fromIndex;
|
||||
}
|
||||
index = (partLength & 0x3f) << 8 | [self.recordData qn_readInt8:index + 1];
|
||||
continue;
|
||||
} else if((partLength & 0xc0) > 0) {
|
||||
return nil;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
|
||||
if (partLength > 0) {
|
||||
if (name.length > 0) {
|
||||
[name appendString:@"."];
|
||||
}
|
||||
|
||||
if (index + partLength > self.recordData.length) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *nameData = [self.recordData subdataWithRange:NSMakeRange(index, partLength)];
|
||||
[name appendString:[[NSString alloc] initWithData:nameData encoding:NSUTF8StringEncoding]];
|
||||
index += partLength;
|
||||
}
|
||||
|
||||
} while (partLength && --maxLoop);
|
||||
|
||||
recordName.name = name;
|
||||
if (recordName.skipLength < 1) {
|
||||
recordName.skipLength = index - fromIndex;
|
||||
}
|
||||
return recordName;
|
||||
}
|
||||
|
||||
- (NSString *)readData:(int)recordType range:(NSRange)range {
|
||||
|
||||
NSString *dataString = nil;
|
||||
NSData *dataValue = [self.recordData subdataWithRange:range];
|
||||
if (recordType == kQNTypeA) {
|
||||
if (dataValue.length == 4) {
|
||||
dataString = [NSString stringWithFormat:@"%d.%d.%d.%d", [dataValue qn_readInt8:0], [dataValue qn_readInt8:1], [dataValue qn_readInt8:2], [dataValue qn_readInt8:3]];
|
||||
}
|
||||
} else if (recordType == kQNTypeAAAA) {
|
||||
if (dataValue.length == 16) {
|
||||
NSMutableString *ipv6 = [NSMutableString string];
|
||||
for (int i=0; i<16; i+=2) {
|
||||
[ipv6 appendFormat:@"%@%02x%02x",(i?@":":@""), [dataValue qn_readInt8:i], [dataValue qn_readInt8:i+1]];
|
||||
}
|
||||
dataString = [ipv6 copy];
|
||||
}
|
||||
} else if (recordType == kQNTypeCname) {
|
||||
if (dataValue.length > 1) {
|
||||
QNDnsRecordName *name = [self getNameFrom:range.location];
|
||||
dataString = [name.name copy];
|
||||
}
|
||||
} else if (recordType == kQNTypeTXT) {
|
||||
if (dataValue.length > 1) {
|
||||
dataString = [[NSString alloc] initWithData:[dataValue subdataWithRange:NSMakeRange(1, dataValue.length - 1)] encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
return dataString;
|
||||
}
|
||||
|
||||
- (void)copyError:(NSError *)error toErrorPoint:(NSError **)errorPoint {
|
||||
if (errorPoint != nil) {
|
||||
*errorPoint = error;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"{messageId:%d, rd:%d, ra:%d, aa:%d, rCode:%d, server:%@, request:%@, answerArray:%@, authorityArray:%@, additionalArray:%@}", self.messageId, self.rd, self.ra, self.aa, self.rCode, self.server, self.request, self.answerArray, self.authorityArray, self.additionalArray];
|
||||
}
|
||||
|
||||
@end
|
||||
47
Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h
generated
Normal file
47
Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// QNDnsServer.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import "QNDnsResolver.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNDnsUdpResolver : QNDnsResolver
|
||||
|
||||
|
||||
/// 构造函数
|
||||
/// @param serverIP 指定 dns local server1. eg:114.114.114.114
|
||||
+ (instancetype)resolverWithServerIP:(NSString *)serverIP;
|
||||
|
||||
/// 构造函数
|
||||
/// @param serverIP 指定 dns local server1. eg:114.114.114.114
|
||||
/// @param recordType 记录类型 eg:kQNTypeA
|
||||
/// @param timeout 超时时间
|
||||
+ (instancetype)resolverWithServerIP:(NSString *)serverIP
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout;
|
||||
|
||||
/// 构造函数
|
||||
/// @param serverIPs 指定多个 dns local server,同时进行 dns 解析,当第一个有效数据返回时结束,或均为解析到数据时结束. eg:@[@"8.8.8.8"]
|
||||
/// @param recordType 记录类型 eg:kQNTypeA
|
||||
/// @param timeout 超时时间
|
||||
+ (instancetype)resolverWithServerIPs:(NSArray <NSString *> *)serverIPs
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout;
|
||||
|
||||
/// 构造函数
|
||||
/// @param serverIPs 指定多个 dns local server,同时进行 dns 解析,当第一个有效数据返回时结束,或均为解析到数据时结束. eg:@[@"8.8.8.8"]
|
||||
/// @param recordType 记录类型 eg:kQNTypeA
|
||||
/// @param queue 多个 udp 包所在的 queue
|
||||
/// @param timeout 超时时间
|
||||
+ (instancetype)resolverWithServerIPs:(NSArray <NSString *> *)serverIPs
|
||||
recordType:(int)recordType
|
||||
queue:(dispatch_queue_t _Nullable)queue
|
||||
timeout:(int)timeout;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
214
Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.m
generated
Normal file
214
Pods/HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.m
generated
Normal file
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// QNDnsServer.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/20.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNDnsError.h"
|
||||
#import "QNDnsResponse.h"
|
||||
#import "QNDnsUdpResolver.h"
|
||||
#import "QNAsyncUdpSocket.h"
|
||||
|
||||
@interface QNDnsFlow : NSObject
|
||||
|
||||
@property(nonatomic, assign)long flowId;
|
||||
@property(nonatomic, copy)NSString *server;
|
||||
@property(nonatomic, strong)QNDnsRequest *dnsRequest;
|
||||
@property(nonatomic, strong)QNAsyncUdpSocket *socket;
|
||||
@property(nonatomic, copy)void(^complete)(QNDnsResponse *response, NSError *error);
|
||||
|
||||
@end
|
||||
@implementation QNDnsFlow
|
||||
@end
|
||||
|
||||
#define kDnsPort 53
|
||||
@interface QNDnsUdpResolver()<QNAsyncUdpSocketDelegate>
|
||||
|
||||
@property(nonatomic, assign)int recordType;
|
||||
@property(nonatomic, assign)int timeout;
|
||||
@property(nonatomic, copy)NSArray *servers;
|
||||
@property(nonatomic, strong)dispatch_queue_t queue;
|
||||
@property(nonatomic, strong)NSMutableDictionary *flows;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNDnsUdpResolver
|
||||
@synthesize recordType;
|
||||
@synthesize timeout;
|
||||
@synthesize servers;
|
||||
|
||||
+ (instancetype)resolverWithServerIP:(NSString *)serverIP {
|
||||
return [self resolverWithServerIP:serverIP recordType:kQNTypeA timeout:QN_DNS_DEFAULT_TIMEOUT];
|
||||
}
|
||||
|
||||
+ (instancetype)resolverWithServerIP:(NSString *)serverIP
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout {
|
||||
return [self resolverWithServerIPs:serverIP ? @[serverIP] : @[] recordType:recordType timeout:timeout];
|
||||
}
|
||||
|
||||
+ (instancetype)resolverWithServerIPs:(NSArray <NSString *> *)serverIPs
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout {
|
||||
return [self resolverWithServerIPs:serverIPs recordType:recordType queue:nil timeout:timeout];
|
||||
}
|
||||
|
||||
+ (instancetype)resolverWithServerIPs:(NSArray <NSString *> *)servers
|
||||
recordType:(int)recordType
|
||||
queue:(dispatch_queue_t _Nullable)queue
|
||||
timeout:(int)timeout {
|
||||
|
||||
QNDnsUdpResolver *resolver = [[self alloc] init];
|
||||
resolver.recordType = recordType;
|
||||
resolver.servers = [servers copy] ?: @[];
|
||||
resolver.timeout = timeout;
|
||||
resolver.queue = queue;
|
||||
return resolver;
|
||||
}
|
||||
|
||||
+ (dispatch_queue_t)defaultQueue {
|
||||
static dispatch_once_t onceToken;
|
||||
static dispatch_queue_t timerQueue;
|
||||
dispatch_once(&onceToken, ^{
|
||||
timerQueue = dispatch_queue_create("com.qiniu.dns.udp.queue", DISPATCH_QUEUE_CONCURRENT);
|
||||
});
|
||||
return timerQueue;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)queue {
|
||||
if (_queue == nil) {
|
||||
_queue = [QNDnsUdpResolver defaultQueue];
|
||||
}
|
||||
return _queue;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)flows {
|
||||
if (_flows == nil) {
|
||||
_flows = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return _flows;
|
||||
}
|
||||
|
||||
- (void)request:(NSString *)server
|
||||
host:(NSString *)host
|
||||
recordType:(int)recordType
|
||||
complete:(void(^)(QNDnsResponse *response, NSError *error))complete {
|
||||
if (complete == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
int messageId = arc4random()%(0xFFFF);
|
||||
QNDnsRequest *dnsRequest = [QNDnsRequest request:messageId recordType:recordType host:host];
|
||||
|
||||
NSError *error = nil;
|
||||
NSData *requestData = [dnsRequest toDnsQuestionData:&error];
|
||||
if (error) {
|
||||
complete(nil, error);
|
||||
return;
|
||||
}
|
||||
|
||||
QNAsyncUdpSocket *socket = [[QNAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:self.queue];
|
||||
// 由系统决定端口号
|
||||
[socket bindToPort:0 error: &error];
|
||||
if (error) {
|
||||
complete(nil, error);
|
||||
return;
|
||||
}
|
||||
|
||||
[socket beginReceiving:&error];
|
||||
if (error) {
|
||||
complete(nil, error);
|
||||
return;
|
||||
}
|
||||
|
||||
QNDnsFlow *flow = [[QNDnsFlow alloc] init];
|
||||
flow.flowId = [socket hash];
|
||||
flow.server = server;
|
||||
flow.dnsRequest = dnsRequest;
|
||||
flow.socket = socket;
|
||||
flow.complete = complete;
|
||||
[self setFlow:flow withId:flow.flowId];
|
||||
|
||||
[socket sendData:requestData toHost:server port:kDnsPort withTimeout:self.timeout tag:flow.flowId];
|
||||
}
|
||||
|
||||
- (void)udpSocketComplete:(QNAsyncUdpSocket *)sock data:(NSData *)data error:(NSError * _Nullable)error {
|
||||
[sock close];
|
||||
|
||||
QNDnsFlow *flow = [self getFlowWithId:[sock hash]];
|
||||
if (!flow) {
|
||||
return;
|
||||
}
|
||||
[self removeFlowWithId:flow.flowId];
|
||||
|
||||
if (error != nil) {
|
||||
flow.complete(nil, error);
|
||||
} else if (data != nil) {
|
||||
NSError *err = nil;
|
||||
QNDnsResponse *response = [QNDnsResponse dnsResponse:flow.server source:QNRecordSourceUdp request:flow.dnsRequest dnsRecordData:data error:&err];
|
||||
flow.complete(response, err);
|
||||
} else {
|
||||
flow.complete(nil, nil);
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -- QNAsyncUdpSocketDelegate
|
||||
- (void)udpSocket:(QNAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address {
|
||||
}
|
||||
|
||||
- (void)udpSocket:(QNAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error {
|
||||
[self udpSocketComplete:sock data:nil error:error];
|
||||
}
|
||||
|
||||
- (void)udpSocket:(QNAsyncUdpSocket *)sock didSendDataWithTag:(long)tag {
|
||||
}
|
||||
|
||||
- (void)udpSocket:(QNAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error {
|
||||
[self udpSocketComplete:sock data:nil error:error];
|
||||
}
|
||||
|
||||
- (void)udpSocket:(QNAsyncUdpSocket *)sock
|
||||
didReceiveData:(NSData *)data
|
||||
fromAddress:(NSData *)address
|
||||
withFilterContext:(nullable id)filterContext {
|
||||
[self udpSocketComplete:sock data:data error:nil];
|
||||
}
|
||||
|
||||
- (void)udpSocketDidClose:(QNAsyncUdpSocket *)sock withError:(NSError * _Nullable)error {
|
||||
[self udpSocketComplete:sock data:nil error:error];
|
||||
}
|
||||
|
||||
|
||||
//MARK: flows
|
||||
- (QNDnsFlow *)getFlowWithId:(long)flowId {
|
||||
NSString *key = [NSString stringWithFormat:@"%ld", flowId];
|
||||
QNDnsFlow *flow = nil;
|
||||
@synchronized (self) {
|
||||
flow = self.flows[key];
|
||||
}
|
||||
return flow;
|
||||
}
|
||||
|
||||
- (BOOL)setFlow:(QNDnsFlow *)flow withId:(long)flowId {
|
||||
if (flow == nil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NSString *key = [NSString stringWithFormat:@"%ld", flowId];
|
||||
@synchronized (self) {
|
||||
self.flows[key] = flow;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)removeFlowWithId:(long)flowId {
|
||||
NSString *key = [NSString stringWithFormat:@"%ld", flowId];
|
||||
@synchronized (self) {
|
||||
[self.flows removeObjectForKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
38
Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.h
generated
Normal file
38
Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.h
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Doh.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/15.
|
||||
//
|
||||
|
||||
#import "QNDnsResolver.h"
|
||||
#import "QNDnsDefine.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface QNDohResolver : QNDnsResolver
|
||||
|
||||
/// 构造函数
|
||||
/// @param server 指定 dns server url。 eg:https://dns.google/dns-query
|
||||
+ (instancetype)resolverWithServer:(NSString *)server;
|
||||
|
||||
/// 构造函数
|
||||
/// @param server 指定 dns server url。 eg:https://dns.google/dns-query
|
||||
/// @param recordType 记录类型 eg:kQNTypeA
|
||||
/// @param timeout 超时时间
|
||||
+ (instancetype)resolverWithServer:(NSString *)server
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout;
|
||||
|
||||
/// 构造函数
|
||||
/// @param servers 指定多个 dns server url,同时进行 dns 解析,当第一个有效数据返回时结束,或均为解析到数据时结束
|
||||
/// eg:https://dns.google/dns-query
|
||||
/// @param recordType 记录类型 eg:kQNTypeA
|
||||
/// @param timeout 超时时间
|
||||
+ (instancetype)resolverWithServers:(NSArray <NSString *> *)servers
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
85
Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.m
generated
Normal file
85
Pods/HappyDNS/HappyDNS/Dns/QNDohResolver.m
generated
Normal file
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Doh.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/15.
|
||||
//
|
||||
#import "QNDnsResponse.h"
|
||||
#import "QNDohResolver.h"
|
||||
|
||||
@interface QNDohResolver()
|
||||
|
||||
@property(nonatomic, assign)int recordType;
|
||||
@property(nonatomic, assign)int timeout;
|
||||
@property(nonatomic, copy)NSArray *servers;
|
||||
|
||||
@end
|
||||
@implementation QNDohResolver
|
||||
@synthesize recordType;
|
||||
@synthesize timeout;
|
||||
@synthesize servers;
|
||||
|
||||
+ (instancetype)resolverWithServer:(NSString *)server {
|
||||
return [self resolverWithServer:server recordType:kQNTypeA timeout:QN_DNS_DEFAULT_TIMEOUT];
|
||||
}
|
||||
|
||||
+ (instancetype)resolverWithServer:(NSString *)server
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout {
|
||||
return [self resolverWithServers:server ? @[server] : @[] recordType:recordType timeout:timeout];
|
||||
}
|
||||
|
||||
+ (instancetype)resolverWithServers:(NSArray <NSString *> *)servers
|
||||
recordType:(int)recordType
|
||||
timeout:(int)timeout {
|
||||
QNDohResolver *resolver = [[self alloc] init];
|
||||
resolver.recordType = recordType;
|
||||
resolver.servers = [servers copy] ?: @[];
|
||||
resolver.timeout = timeout;
|
||||
return resolver;
|
||||
}
|
||||
|
||||
- (void)request:(NSString *)server
|
||||
host:(NSString *)host
|
||||
recordType:(int)recordType
|
||||
complete:(void(^)(QNDnsResponse *response, NSError *error))complete {
|
||||
if (complete == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (host == nil || host.length == 0) {
|
||||
complete(nil, kQNDnsInvalidParamError(@"host can not empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
int messageId = arc4random()%(0xFFFF);
|
||||
QNDnsRequest *dnsRequest = [QNDnsRequest request:messageId recordType:recordType host:host];
|
||||
NSError *error = nil;
|
||||
NSData *requestData = [dnsRequest toDnsQuestionData:&error];
|
||||
if (error) {
|
||||
complete(nil, error);
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:server]];
|
||||
request.HTTPMethod = @"POST";
|
||||
request.HTTPBody = requestData;
|
||||
request.timeoutInterval = self.timeout;
|
||||
[request addValue:@"application/dns-message" forHTTPHeaderField:@"Content-Type"];
|
||||
[request addValue:@"application/dns-message" forHTTPHeaderField:@"Accept"];
|
||||
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
complete(nil, error);
|
||||
} else if (data) {
|
||||
QNDnsResponse *dnsResponse = [QNDnsResponse dnsResponse:server source:QNRecordSourceDoh request:dnsRequest dnsRecordData:data error:nil];
|
||||
complete(dnsResponse, nil);
|
||||
} else {
|
||||
complete(nil, nil);
|
||||
}
|
||||
}];
|
||||
[task resume];
|
||||
}
|
||||
|
||||
@end
|
||||
25
Pods/HappyDNS/HappyDNS/HappyDNS.h
generated
Normal file
25
Pods/HappyDNS/HappyDNS/HappyDNS.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// HappyDNS.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/24.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "QNDnsError.h"
|
||||
#import "QNDnsManager.h"
|
||||
#import "QNDnspodEnterprise.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNDnsResolver.h"
|
||||
#import "QNDnsUdpResolver.h"
|
||||
#import "QNDohResolver.h"
|
||||
#import "QNDnsDefine.h"
|
||||
#import "QNHijackingDetectWrapper.h"
|
||||
#import "QNIP.h"
|
||||
#import "QNNetworkInfo.h"
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolver.h"
|
||||
#import "QNResolverDelegate.h"
|
||||
#import "QNGetAddrInfo.h"
|
||||
30
Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h
generated
Normal file
30
Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// QNDnspodEnterprise.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/7/31.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNResolverDelegate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern const int kQN_ENCRYPT_FAILED;
|
||||
extern const int kQN_DECRYPT_FAILED;
|
||||
|
||||
@interface QNDnspodEnterprise : NSObject <QNResolverDelegate>
|
||||
|
||||
- (instancetype)initWithId:(NSString *)userId
|
||||
key:(NSString *)key;
|
||||
|
||||
- (instancetype)initWithId:(NSString *)userId
|
||||
key:(NSString *)key
|
||||
server:(NSString *)server;
|
||||
|
||||
- (instancetype)initWithId:(NSString *)userId
|
||||
key:(NSString *)key
|
||||
server:(NSString *)server
|
||||
timeout:(NSUInteger)time;
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
|
||||
@end
|
||||
141
Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.m
generated
Normal file
141
Pods/HappyDNS/HappyDNS/Http/QNDnspodEnterprise.m
generated
Normal file
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// QNDnspodEnterprise.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNDnspodEnterprise.h"
|
||||
#import <CommonCrypto/CommonCryptor.h>
|
||||
|
||||
#import "QNDes.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNHex.h"
|
||||
#import "QNIP.h"
|
||||
#import "QNRecord.h"
|
||||
|
||||
const int kQN_ENCRYPT_FAILED = -10001;
|
||||
const int kQN_DECRYPT_FAILED = -10002;
|
||||
|
||||
@interface QNDnspodEnterprise ()
|
||||
@property (readonly, strong) NSString *server;
|
||||
@property (nonatomic, strong) NSString *userId;
|
||||
@property (nonatomic, strong) QNDes *des;
|
||||
@property (nonatomic) NSUInteger timeout;
|
||||
|
||||
@end
|
||||
|
||||
@implementation QNDnspodEnterprise
|
||||
|
||||
- (instancetype)initWithId:(NSString *)userId
|
||||
key:(NSString *)key {
|
||||
return [self initWithId:userId key:key server:@"119.29.29.98"];
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(NSString *)userId
|
||||
key:(NSString *)key
|
||||
server:(NSString *)server {
|
||||
return [self initWithId:userId key:key server:@"119.29.29.98" timeout:QN_DNS_DEFAULT_TIMEOUT];
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(NSString *)userId
|
||||
key:(NSString *)key
|
||||
server:(NSString *)server
|
||||
timeout:(NSUInteger)time {
|
||||
if (self = [super init]) {
|
||||
_server = server;
|
||||
_userId = userId;
|
||||
_des = [[QNDes alloc] init:[key dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
_timeout = time;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)encrypt:(NSString *)domain {
|
||||
NSData *data = [_des encrypt:[domain dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSString *str = [QNHex encodeHexData:data];
|
||||
return str;
|
||||
}
|
||||
|
||||
- (NSString *)decrypt:(NSData *)raw {
|
||||
NSData *enc = [QNHex decodeHexString:[[NSString alloc] initWithData:raw
|
||||
encoding:NSUTF8StringEncoding]];
|
||||
if (enc == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [_des decrpyt:enc];
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
|
||||
NSString *encrypt = [self encrypt:domain.domain];
|
||||
if (encrypt == nil) {
|
||||
if (error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:domain.domain code:kQN_ENCRYPT_FAILED userInfo:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
__block NSData *data = nil;
|
||||
__block NSError *httpError = nil;
|
||||
__block NSHTTPURLResponse *response = nil;
|
||||
NSString *url = [NSString stringWithFormat:@"http://%@/d?ttl=1&dn=%@&id=%@", [QNIP ipHost:_server], encrypt, _userId];
|
||||
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:_timeout];
|
||||
NSURLSession *session = [NSURLSession sharedSession];
|
||||
NSURLSessionTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable resp, NSError * _Nullable error) {
|
||||
|
||||
data = data;
|
||||
httpError = error;
|
||||
response = (NSHTTPURLResponse *)resp;
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
}];
|
||||
[task resume];
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
if (httpError != nil) {
|
||||
if (error != nil) {
|
||||
*error = httpError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
if (response.statusCode != 200) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *raw = [self decrypt:data];
|
||||
if (raw == nil) {
|
||||
if (error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:domain.domain code:kQN_DECRYPT_FAILED userInfo:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
NSArray *ip1 = [raw componentsSeparatedByString:@","];
|
||||
if (ip1.count != 2) {
|
||||
return nil;
|
||||
}
|
||||
NSString *ttlStr = [ip1 objectAtIndex:1];
|
||||
int ttl = [ttlStr intValue];
|
||||
if (ttl <= 0) {
|
||||
return nil;
|
||||
}
|
||||
NSString *ips = [ip1 objectAtIndex:0];
|
||||
NSArray *ipArray = [ips componentsSeparatedByString:@";"];
|
||||
NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:ipArray.count];
|
||||
for (int i = 0; i < ipArray.count; i++) {
|
||||
QNRecord *record = [[QNRecord alloc] init:[ipArray objectAtIndex:i] ttl:ttl type:kQNTypeA source:QNRecordSourceDnspodEnterprise];
|
||||
[ret addObject:record];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
17
Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h
generated
Normal file
17
Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// QNHijackingDetectWrapper.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/7/16.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "QNResolverDelegate.h"
|
||||
|
||||
@class QNResolver;
|
||||
@interface QNHijackingDetectWrapper : NSObject <QNResolverDelegate>
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
|
||||
- (instancetype)initWithResolver:(QNResolver *)resolver;
|
||||
@end
|
||||
51
Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.m
generated
Normal file
51
Pods/HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.m
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// QNHijackingDetectWrapper.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/7/16.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNHijackingDetectWrapper.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolver.h"
|
||||
|
||||
@interface QNHijackingDetectWrapper ()
|
||||
@property (nonatomic, readonly) QNResolver *resolver;
|
||||
@end
|
||||
|
||||
@implementation QNHijackingDetectWrapper
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
|
||||
NSArray *result = [_resolver query:domain networkInfo:netInfo error:error];
|
||||
if (((!domain.hasCname) && domain.maxTtl == 0) || result == nil || result.count == 0) {
|
||||
return result;
|
||||
}
|
||||
BOOL hasCname = NO;
|
||||
BOOL outOfTtl = NO;
|
||||
for (int i = 0; i < result.count; i++) {
|
||||
QNRecord *record = [result objectAtIndex:i];
|
||||
if (record.type == kQNTypeCname) {
|
||||
hasCname = YES;
|
||||
}
|
||||
if (domain.maxTtl > 0 && record.type == kQNTypeA && record.ttl > domain.maxTtl) {
|
||||
outOfTtl = YES;
|
||||
}
|
||||
}
|
||||
if ((domain.hasCname && !hasCname) || outOfTtl) {
|
||||
if (error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:domain.domain code:kQNDomainHijackingCode userInfo:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
- (instancetype)initWithResolver:(QNResolver *)resolver {
|
||||
if (self = [super init]) {
|
||||
_resolver = resolver;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
20
Pods/HappyDNS/HappyDNS/Local/QNHosts.h
generated
Normal file
20
Pods/HappyDNS/HappyDNS/Local/QNHosts.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// QNHosts.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolverDelegate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNHosts : NSObject
|
||||
|
||||
- (NSArray <QNRecord *> *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo;
|
||||
|
||||
- (void)put:(NSString *)domain record:(QNRecord *)record;
|
||||
- (void)put:(NSString *)domain record:(QNRecord *)record provider:(int)provider;
|
||||
|
||||
@end
|
||||
111
Pods/HappyDNS/HappyDNS/Local/QNHosts.m
generated
Normal file
111
Pods/HappyDNS/HappyDNS/Local/QNHosts.m
generated
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// QNHosts.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNHosts.h"
|
||||
#import "QNDomain.h"
|
||||
#import "QNNetworkInfo.h"
|
||||
|
||||
@interface QNHostsValue : NSObject
|
||||
@property (nonatomic, copy, readonly) QNRecord *record;
|
||||
@property (readonly) int provider;
|
||||
@end
|
||||
|
||||
@implementation QNHostsValue
|
||||
|
||||
- (instancetype)init:(QNRecord *)record provider:(int)provider {
|
||||
if (self = [super init]) {
|
||||
_record = record;
|
||||
_provider = provider;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static NSArray<QNHostsValue *> *filter(NSArray *input, int provider) {
|
||||
NSMutableArray<QNHostsValue *> *normal = [[NSMutableArray alloc] initWithCapacity:input.count];
|
||||
NSMutableArray<QNHostsValue *> *special = [[NSMutableArray alloc] init];
|
||||
for (QNHostsValue *v in input) {
|
||||
if (v.provider == kQNISP_GENERAL) {
|
||||
[normal addObject:v];
|
||||
} else if (provider == v.provider) {
|
||||
[special addObject:v];
|
||||
}
|
||||
}
|
||||
if (special.count != 0) {
|
||||
return special;
|
||||
}
|
||||
return [normal copy];
|
||||
}
|
||||
|
||||
@interface QNHosts ()
|
||||
@property (nonatomic) NSMutableDictionary *dict;
|
||||
@end
|
||||
|
||||
@implementation QNHosts
|
||||
- (NSArray <QNRecord *> *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo {
|
||||
NSMutableArray *x;
|
||||
@synchronized(_dict) {
|
||||
x = [_dict objectForKey:domain.domain];
|
||||
}
|
||||
|
||||
if (x == nil || x.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@synchronized (_dict) {
|
||||
if (x.count >= 2) {
|
||||
QNHostsValue *first = [x firstObject];
|
||||
[x removeObjectAtIndex:0];
|
||||
[x addObject:first];
|
||||
}
|
||||
}
|
||||
|
||||
NSArray <QNHostsValue *> *values = filter([x copy], netInfo.provider);
|
||||
return [self toRecords:values];
|
||||
}
|
||||
|
||||
- (NSArray <QNRecord *> *)toRecords:(NSArray <QNHostsValue *> *)values {
|
||||
if (values == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSMutableArray<QNRecord *> *records = [NSMutableArray array];
|
||||
for (QNHostsValue *value in values) {
|
||||
if (value.record != nil && value.record.value != nil) {
|
||||
[records addObject:value.record];
|
||||
}
|
||||
}
|
||||
return [records copy];
|
||||
}
|
||||
|
||||
|
||||
- (void)put:(NSString *)domain record:(QNRecord *)record {
|
||||
[self put:domain record:record provider:kQNISP_GENERAL];
|
||||
}
|
||||
|
||||
- (void)put:(NSString *)domain record:(QNRecord *)record provider:(int)provider {
|
||||
QNHostsValue *v = [[QNHostsValue alloc] init:record provider:provider];
|
||||
@synchronized(_dict) {
|
||||
NSMutableArray *x = [_dict objectForKey:domain];
|
||||
if (x == nil) {
|
||||
x = [[NSMutableArray alloc] init];
|
||||
}
|
||||
[x addObject:v];
|
||||
[_dict setObject:x forKey:domain];
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_dict = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
16
Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.h
generated
Normal file
16
Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.h
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// QNResolv.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/5/28.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef QNResolv_h
|
||||
#define QNResolv_h
|
||||
|
||||
extern BOOL isV6(NSString *address);
|
||||
|
||||
extern int setup_dns_server(void *res, NSString *dns_server, NSUInteger timeout);
|
||||
|
||||
#endif /* QNResolv_h */
|
||||
84
Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.m
generated
Normal file
84
Pods/HappyDNS/HappyDNS/Local/QNResolvUtil.m
generated
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// QNResolvUtil.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/5/28.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#import "QNIP.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
BOOL isV6(NSString *address) {
|
||||
return strchr(address.UTF8String, ':') != NULL;
|
||||
}
|
||||
|
||||
int setup_dns_server(void *_res_state, NSString *dns_server, NSUInteger timeout) {
|
||||
res_state res = (res_state)_res_state;
|
||||
int r = res_ninit(res);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
}
|
||||
res->retrans = (int)timeout;
|
||||
res->retry = 1;
|
||||
if (dns_server == nil) {
|
||||
return 0;
|
||||
}
|
||||
res->options |= RES_IGNTC;
|
||||
|
||||
union res_sockaddr_union server = {0};
|
||||
|
||||
struct addrinfo hints = {0}, *ai = NULL;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
int ret = getaddrinfo(dns_server.UTF8String, "53", &hints, &ai);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
int family = ai->ai_family;
|
||||
|
||||
if (family == AF_INET6) {
|
||||
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
|
||||
server.sin6 = *((struct sockaddr_in6 *)ai->ai_addr);
|
||||
} else {
|
||||
server.sin = *((struct sockaddr_in *)ai->ai_addr);
|
||||
}
|
||||
|
||||
if (![QNIP isIpV6FullySupported] && family == AF_INET) {
|
||||
if ([QNIP isV6]) {
|
||||
freeaddrinfo(ai);
|
||||
ai = NULL;
|
||||
bzero(&hints, (size_t)0);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
char buf[64] = {0};
|
||||
qn_nat64(buf, sizeof(buf), (uint32_t)server.sin.sin_addr.s_addr);
|
||||
int ret = getaddrinfo(buf, "53", &hints, &ai);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
|
||||
server.sin6 = *((struct sockaddr_in6 *)ai->ai_addr);
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
res_setservers(res, &server, 1);
|
||||
return 0;
|
||||
}
|
||||
25
Pods/HappyDNS/HappyDNS/Local/QNResolver.h
generated
Normal file
25
Pods/HappyDNS/HappyDNS/Local/QNResolver.h
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// QNResolver.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNResolverDelegate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNResolver : NSObject <QNResolverDelegate>
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
|
||||
|
||||
// @deprecated typo
|
||||
- (instancetype)initWithAddres:(NSString *)address DEPRECATED_ATTRIBUTE;
|
||||
|
||||
- (instancetype)initWithAddress:(NSString *)address;
|
||||
|
||||
- (instancetype)initWithAddress:(NSString *)address
|
||||
timeout:(NSUInteger)time;
|
||||
|
||||
+ (instancetype)systemResolver;
|
||||
+ (NSString *)systemDnsServer;
|
||||
@end
|
||||
153
Pods/HappyDNS/HappyDNS/Local/QNResolver.m
generated
Normal file
153
Pods/HappyDNS/HappyDNS/Local/QNResolver.m
generated
Normal file
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// QNResolver.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/6/23.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#import "QNDomain.h"
|
||||
#import "QNIP.h"
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolver.h"
|
||||
|
||||
#import "QNResolvUtil.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
@interface QNResolver ()
|
||||
@property (nonatomic, readonly, strong) NSString *address;
|
||||
@property (nonatomic, readonly) NSUInteger timeout;
|
||||
@end
|
||||
|
||||
static NSArray *query_ip_v4(res_state res, const char *host) {
|
||||
u_char answer[2000];
|
||||
int len = res_nquery(res, host, ns_c_in, ns_t_a, answer, sizeof(answer));
|
||||
|
||||
ns_msg handle;
|
||||
ns_initparse(answer, len, &handle);
|
||||
|
||||
int count = ns_msg_count(handle, ns_s_an);
|
||||
if (count <= 0) {
|
||||
res_ndestroy(res);
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:count];
|
||||
char buf[32];
|
||||
char cnameBuf[NS_MAXDNAME];
|
||||
memset(cnameBuf, 0, sizeof(cnameBuf));
|
||||
for (int i = 0; i < count; i++) {
|
||||
ns_rr rr;
|
||||
if (ns_parserr(&handle, ns_s_an, i, &rr) != 0) {
|
||||
res_ndestroy(res);
|
||||
return nil;
|
||||
}
|
||||
int t = ns_rr_type(rr);
|
||||
int ttl = ns_rr_ttl(rr);
|
||||
NSString *val;
|
||||
if (t == ns_t_a) {
|
||||
const char *p = inet_ntop(AF_INET, ns_rr_rdata(rr), buf, sizeof(buf));
|
||||
val = [NSString stringWithUTF8String:p];
|
||||
} else if (t == ns_t_cname) {
|
||||
int x = ns_name_uncompress(answer, &(answer[len]), ns_rr_rdata(rr), cnameBuf, sizeof(cnameBuf));
|
||||
if (x <= 0) {
|
||||
continue;
|
||||
}
|
||||
val = [NSString stringWithUTF8String:cnameBuf];
|
||||
memset(cnameBuf, 0, sizeof(cnameBuf));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
QNRecord *record = [[QNRecord alloc] init:val ttl:ttl type:t source:QNRecordSourceSystem];
|
||||
[array addObject:record];
|
||||
}
|
||||
res_ndestroy(res);
|
||||
return array;
|
||||
}
|
||||
|
||||
@implementation QNResolver
|
||||
- (instancetype)initWithAddres:(NSString *)address {
|
||||
return [self initWithAddress:address];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAddress:(NSString *)address {
|
||||
return [self initWithAddress:address timeout:QN_DNS_DEFAULT_TIMEOUT];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAddress:(NSString *)address
|
||||
timeout:(NSUInteger)time {
|
||||
if (self = [super init]) {
|
||||
_address = address;
|
||||
_timeout = time;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
|
||||
struct __res_state res;
|
||||
|
||||
int r = setup_dns_server(&res, _address, _timeout);
|
||||
if (r != 0) {
|
||||
if (error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:kQNDomainSeverError userInfo:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *ret = query_ip_v4(&res, [domain.domain cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
if (ret != nil && ret.count != 0) {
|
||||
return ret;
|
||||
}
|
||||
if (error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:NSURLErrorDNSLookupFailed userInfo:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (instancetype)systemResolver {
|
||||
return [[QNResolver alloc] initWithAddress:nil];
|
||||
}
|
||||
|
||||
+ (NSString *)systemDnsServer {
|
||||
struct __res_state res;
|
||||
int r = res_ninit(&res);
|
||||
if (r != 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
union res_sockaddr_union server[MAXNS] = {0};
|
||||
r = res_getservers(&res, server, MAXNS);
|
||||
res_ndestroy(&res);
|
||||
if (r <= 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
int family = server[0].sin.sin_family;
|
||||
char buf[64] = {0};
|
||||
const void *addr;
|
||||
if (family == AF_INET6) {
|
||||
addr = &server[0].sin6.sin6_addr;
|
||||
} else {
|
||||
addr = &server[0].sin.sin_addr;
|
||||
}
|
||||
const char *p = inet_ntop(family, addr, buf, sizeof(buf));
|
||||
if (p == NULL) {
|
||||
return nil;
|
||||
}
|
||||
return [NSString stringWithUTF8String:p];
|
||||
}
|
||||
|
||||
@end
|
||||
23
Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.h
generated
Normal file
23
Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.h
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// QNTxtResolver.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/1/5.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNResolverDelegate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNTxtResolver : NSObject <QNResolverDelegate>
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error;
|
||||
|
||||
/**
|
||||
* 根据服务器地址进行初始化
|
||||
*
|
||||
* @param address DNS 服务器地址,nil 表示系统的
|
||||
*/
|
||||
- (instancetype)initWithAddress:(NSString *)address;
|
||||
|
||||
- (instancetype)initWithAddress:(NSString *)address timeout:(NSUInteger)time;
|
||||
@end
|
||||
109
Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.m
generated
Normal file
109
Pods/HappyDNS/HappyDNS/Local/QNTxtResolver.m
generated
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// QNTxtResolver.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/1/5.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNTxtResolver.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <resolv.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#import "QNDomain.h"
|
||||
#import "QNRecord.h"
|
||||
#import "QNResolvUtil.h"
|
||||
#import "QNResolver.h"
|
||||
|
||||
@interface QNTxtResolver ()
|
||||
@property (nonatomic, readonly, strong) NSString *address;
|
||||
@property (nonatomic, readonly) NSUInteger timeout;
|
||||
@end
|
||||
|
||||
static NSArray *query_ip(res_state res, const char *host) {
|
||||
u_char answer[1500];
|
||||
int len = res_nquery(res, host, ns_c_in, ns_t_txt, answer, sizeof(answer));
|
||||
|
||||
ns_msg handle;
|
||||
ns_initparse(answer, len, &handle);
|
||||
|
||||
int count = ns_msg_count(handle, ns_s_an);
|
||||
if (count != 1) {
|
||||
res_ndestroy(res);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char txtbuf[256];
|
||||
memset(txtbuf, 0, sizeof(txtbuf));
|
||||
|
||||
ns_rr rr;
|
||||
if (ns_parserr(&handle, ns_s_an, 0, &rr) != 0) {
|
||||
res_ndestroy(res);
|
||||
return nil;
|
||||
}
|
||||
int t = ns_rr_type(rr);
|
||||
int ttl = ns_rr_ttl(rr);
|
||||
int rdlen = ns_rr_rdlen(rr);
|
||||
if (rdlen <= 1 + 7) {
|
||||
res_ndestroy(res);
|
||||
return nil;
|
||||
}
|
||||
NSString *val;
|
||||
if (t == ns_t_txt) {
|
||||
memcpy(txtbuf, ns_rr_rdata(rr) + 1, rdlen - 1);
|
||||
val = [NSString stringWithUTF8String:txtbuf];
|
||||
} else {
|
||||
res_ndestroy(res);
|
||||
return nil;
|
||||
}
|
||||
NSArray *ipArray = [val componentsSeparatedByString:@","];
|
||||
NSMutableArray *ret = [[NSMutableArray alloc] initWithCapacity:ipArray.count];
|
||||
for (int i = 0; i < ipArray.count; i++) {
|
||||
QNRecord *record = [[QNRecord alloc] init:[ipArray objectAtIndex:i] ttl:ttl type:kQNTypeA source:QNRecordSourceSystem];
|
||||
[ret addObject:record];
|
||||
}
|
||||
|
||||
res_ndestroy(res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@implementation QNTxtResolver
|
||||
- (instancetype)initWithAddress:(NSString *)address {
|
||||
return [self initWithAddress:address timeout:QN_DNS_DEFAULT_TIMEOUT];
|
||||
}
|
||||
|
||||
- (instancetype)initWithAddress:(NSString *)address timeout:(NSUInteger)time {
|
||||
if (self = [super init]) {
|
||||
_address = address;
|
||||
_timeout = time;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray *)query:(QNDomain *)domain networkInfo:(QNNetworkInfo *)netInfo error:(NSError *__autoreleasing *)error {
|
||||
struct __res_state res;
|
||||
|
||||
int r = setup_dns_server(&res, _address, _timeout);
|
||||
if (r != 0) {
|
||||
if (error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:kQNDomainSeverError userInfo:nil];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *ret = query_ip(&res, [domain.domain cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
if (ret == nil && error != nil) {
|
||||
*error = [[NSError alloc] initWithDomain:@"qiniu.dns" code:NSURLErrorDNSLookupFailed userInfo:nil];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
14
Pods/HappyDNS/HappyDNS/PrivacyInfo.xcprivacy
generated
Normal file
14
Pods/HappyDNS/HappyDNS/PrivacyInfo.xcprivacy
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
75
Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.h
generated
Normal file
75
Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.h
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// NSMutableData+QNWriter.h
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/16.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSData (QNReader)
|
||||
|
||||
//MARK: 读数据
|
||||
- (uint8_t)qn_readInt8:(NSInteger)from;
|
||||
|
||||
- (uint16_t)qn_readLittleEndianInt16:(NSInteger)from;
|
||||
- (uint32_t)qn_readLittleEndianInt32:(NSInteger)from;
|
||||
- (uint64_t)qn_readLittleEndianInt64:(NSInteger)from;
|
||||
|
||||
- (uint16_t)qn_readBigEndianInt16:(NSInteger)from;
|
||||
- (uint32_t)qn_readBigEndianInt32:(NSInteger)from;
|
||||
- (uint64_t)qn_readBigEndianInt64:(NSInteger)from;
|
||||
|
||||
- (int8_t)qn_readSInt8:(NSInteger)from;
|
||||
- (int16_t)qn_readLittleEndianSInt16:(NSInteger)from;
|
||||
- (int32_t)qn_readLittleEndianSInt32:(NSInteger)from;
|
||||
- (int64_t)qn_readLittleEndianSInt64:(NSInteger)from;
|
||||
|
||||
- (int16_t)qn_readBigEndianSInt16:(NSInteger)from;
|
||||
- (int32_t)qn_readBigEndianSInt32:(NSInteger)from;
|
||||
- (int64_t)qn_readBigEndianSInt64:(NSInteger)from;
|
||||
|
||||
- (float)qn_readFloat:(NSInteger)from;
|
||||
- (double)qn_readDouble:(NSInteger)from;
|
||||
|
||||
- (float)qn_readSwappedFloat:(NSInteger)from;
|
||||
- (double)qn_readSwappedDouble:(NSInteger)from;
|
||||
|
||||
- (NSString *)qn_readString:(NSRange)range usingEncoding:(NSStringEncoding)encoding;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface NSMutableData (QNWriter)
|
||||
|
||||
//MARK: 写数据
|
||||
- (void)qn_appendInt8:(uint8_t)value;
|
||||
|
||||
- (void)qn_appendLittleEndianInt16:(uint16_t)value;
|
||||
- (void)qn_appendLittleEndianInt32:(uint32_t)value;
|
||||
- (void)qn_appendLittleEndianInt64:(uint64_t)value;
|
||||
|
||||
- (void)qn_appendBigEndianInt16:(uint16_t)value;
|
||||
- (void)qn_appendBigEndianInt32:(uint32_t)value;
|
||||
- (void)qn_appendBigEndianInt64:(uint64_t)value;
|
||||
|
||||
- (void)qn_appendSInt8:(int8_t)value;
|
||||
|
||||
- (void)qn_appendLittleEndianSInt16:(int16_t)value;
|
||||
- (void)qn_appendLittleEndianSInt32:(int32_t)value;
|
||||
- (void)qn_appendLittleEndianSInt64:(int64_t)value;
|
||||
|
||||
- (void)qn_appendBigEndianSInt16:(int16_t)value;
|
||||
- (void)qn_appendBigEndianSInt32:(int32_t)value;
|
||||
- (void)qn_appendBigEndianSInt64:(int64_t)value;
|
||||
|
||||
// These methods append floating point values depending on the architecture of your processor
|
||||
// they're usually not appropriate for network transmission
|
||||
- (void)qn_appendFloat:(float)value;
|
||||
- (void)qn_appendDouble:(double)value;
|
||||
|
||||
- (void)qn_appendSwappedFloat:(float)value;
|
||||
- (void)qn_appendSwappedDouble:(double)value;
|
||||
|
||||
- (void)qn_appendString:(NSString *)value usingEncoding:(NSStringEncoding)encoding;
|
||||
|
||||
@end
|
||||
151
Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.m
generated
Normal file
151
Pods/HappyDNS/HappyDNS/Util/NSData+QNRW.m
generated
Normal file
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// NSMutableData+QNWriter.m
|
||||
// Doh
|
||||
//
|
||||
// Created by yangsen on 2021/7/16.
|
||||
//
|
||||
#import "NSData+QNRW.h"
|
||||
|
||||
@implementation NSData (QNReader)
|
||||
|
||||
//MARK: 读数据
|
||||
- (uint8_t)qn_readInt8:(NSInteger)from {
|
||||
uint8_t value = 0;
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)];
|
||||
return value;
|
||||
}
|
||||
|
||||
#define READ_METHOD(endian, size) \
|
||||
- (uint ## size ## _t)qn_read ## endian ## EndianInt ## size:(NSInteger)from { \
|
||||
uint ## size ## _t value = 0; \
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; \
|
||||
value = CFSwapInt ## size ## HostTo ## endian(value); \
|
||||
return value; \
|
||||
}
|
||||
|
||||
READ_METHOD(Little, 16)
|
||||
READ_METHOD(Little, 32)
|
||||
READ_METHOD(Little, 64)
|
||||
READ_METHOD(Big, 16)
|
||||
READ_METHOD(Big, 32)
|
||||
READ_METHOD(Big, 64)
|
||||
|
||||
#undef READ_METHOD
|
||||
|
||||
- (int8_t)qn_readSInt8:(NSInteger)from {
|
||||
int8_t value = 0;
|
||||
[[self subdataWithRange:NSMakeRange(from, 8)] getBytes:&value length:sizeof(value)];
|
||||
return value;
|
||||
}
|
||||
|
||||
#define READ_METHOD(endian, size) \
|
||||
- (int ## size ## _t)qn_read ## endian ## EndianSInt ## size:(NSInteger)from { \
|
||||
int ## size ## _t value = 0; \
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)]; \
|
||||
value = CFSwapInt ## size ## HostTo ## endian(value); \
|
||||
return value; \
|
||||
}
|
||||
|
||||
READ_METHOD(Little, 16)
|
||||
READ_METHOD(Little, 32)
|
||||
READ_METHOD(Little, 64)
|
||||
READ_METHOD(Big, 16)
|
||||
READ_METHOD(Big, 32)
|
||||
READ_METHOD(Big, 64)
|
||||
|
||||
#undef READ_METHOD
|
||||
|
||||
|
||||
- (float)qn_readFloat:(NSInteger)from {
|
||||
float value = 0;
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)];
|
||||
return value;
|
||||
}
|
||||
|
||||
- (double)qn_readDouble:(NSInteger)from {
|
||||
double value = 0;
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)];
|
||||
return value;
|
||||
}
|
||||
|
||||
- (float)qn_readSwappedFloat:(NSInteger)from {
|
||||
CFSwappedFloat32 value;
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)];
|
||||
return CFConvertFloatSwappedToHost(value);
|
||||
}
|
||||
|
||||
- (double)qn_readSwappedDouble:(NSInteger)from {
|
||||
CFSwappedFloat64 value;
|
||||
[[self subdataWithRange:NSMakeRange(from, sizeof(value))] getBytes:&value length:sizeof(value)];
|
||||
return CFConvertDoubleSwappedToHost(value);
|
||||
}
|
||||
|
||||
- (NSString *)qn_readString:(NSRange)range usingEncoding:(NSStringEncoding)encoding {
|
||||
NSData *value = [self subdataWithRange:range];
|
||||
return [[NSString alloc] initWithData:value encoding:encoding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSMutableData (QNWriter)
|
||||
|
||||
- (void)qn_appendInt8:(uint8_t)value {
|
||||
[self appendBytes:&value length:sizeof(value)];
|
||||
}
|
||||
|
||||
#define APPEND_METHOD(endian, size) \
|
||||
- (void)qn_append ## endian ## EndianInt ## size:(uint ## size ## _t)value { \
|
||||
value = CFSwapInt ## size ## HostTo ## endian(value); \
|
||||
[self appendBytes:&value length:sizeof(value)]; \
|
||||
}
|
||||
|
||||
APPEND_METHOD(Little, 16)
|
||||
APPEND_METHOD(Little, 32)
|
||||
APPEND_METHOD(Little, 64)
|
||||
APPEND_METHOD(Big, 16)
|
||||
APPEND_METHOD(Big, 32)
|
||||
APPEND_METHOD(Big, 64)
|
||||
|
||||
#undef APPEND_METHOD
|
||||
|
||||
- (void)qn_appendSInt8:(int8_t)value {
|
||||
[self qn_appendInt8:*(int8_t *)&value];
|
||||
}
|
||||
|
||||
#define APPEND_METHOD(endian, size) \
|
||||
- (void)qn_append ## endian ## EndianSInt ## size:(int ## size ## _t)value { \
|
||||
[self qn_append ## endian ## EndianInt ## size:*(uint ## size ## _t *)&value]; \
|
||||
}
|
||||
|
||||
APPEND_METHOD(Little, 16)
|
||||
APPEND_METHOD(Little, 32)
|
||||
APPEND_METHOD(Little, 64)
|
||||
APPEND_METHOD(Big, 16)
|
||||
APPEND_METHOD(Big, 32)
|
||||
APPEND_METHOD(Big, 64)
|
||||
|
||||
#undef APPEND_METHOD
|
||||
|
||||
- (void)qn_appendFloat:(float)value {
|
||||
[self appendBytes:&value length:sizeof(value)];
|
||||
}
|
||||
|
||||
- (void)qn_appendDouble:(double)value {
|
||||
[self appendBytes:&value length:sizeof(value)];
|
||||
}
|
||||
|
||||
- (void)qn_appendSwappedFloat:(float)value {
|
||||
CFSwappedFloat32 v = CFConvertFloatHostToSwapped(value);
|
||||
[self appendBytes:&v length:sizeof(value)];
|
||||
}
|
||||
|
||||
- (void)qn_appendSwappedDouble:(double)value {
|
||||
CFSwappedFloat64 v = CFConvertDoubleHostToSwapped(value);
|
||||
[self appendBytes:&v length:sizeof(value)];
|
||||
}
|
||||
|
||||
- (void)qn_appendString:(NSString *)value usingEncoding:(NSStringEncoding)encoding {
|
||||
[self appendData:[value dataUsingEncoding:encoding]];
|
||||
}
|
||||
|
||||
@end
|
||||
1024
Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h
generated
Normal file
1024
Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h
generated
Normal file
File diff suppressed because it is too large
Load Diff
5517
Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.m
generated
Executable file
5517
Pods/HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.m
generated
Executable file
File diff suppressed because it is too large
Load Diff
22
Pods/HappyDNS/HappyDNS/Util/QNDes.h
generated
Normal file
22
Pods/HappyDNS/HappyDNS/Util/QNDes.h
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// QNDes.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/8/1.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern const int kQN_ENCRYPT_FAILED;
|
||||
extern const int kQN_DECRYPT_FAILED;
|
||||
|
||||
@interface QNDes : NSObject
|
||||
|
||||
- (NSData *)encrypt:(NSData *)input;
|
||||
|
||||
- (NSData *)decrpyt:(NSData *)input;
|
||||
|
||||
- (instancetype)init:(NSData *)key;
|
||||
|
||||
@end
|
||||
92
Pods/HappyDNS/HappyDNS/Util/QNDes.m
generated
Normal file
92
Pods/HappyDNS/HappyDNS/Util/QNDes.m
generated
Normal file
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// QNDes.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/8/1.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <CommonCrypto/CommonCryptor.h>
|
||||
|
||||
#import "QNDes.h"
|
||||
|
||||
@interface QNDes ()
|
||||
@property (nonatomic, strong) NSData *key;
|
||||
@end
|
||||
|
||||
@implementation QNDes
|
||||
|
||||
- (NSData *)encrypt:(NSData *)data {
|
||||
const void *input = data.bytes;
|
||||
size_t inputSize = data.length;
|
||||
|
||||
size_t bufferSize = (inputSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
|
||||
uint8_t *buffer = malloc(bufferSize * sizeof(uint8_t));
|
||||
memset((void *)buffer, 0x0, bufferSize);
|
||||
size_t movedBytes = 0;
|
||||
|
||||
const void *vkey = _key.bytes;
|
||||
|
||||
CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt,
|
||||
kCCAlgorithmDES,
|
||||
kCCOptionECBMode | kCCOptionPKCS7Padding,
|
||||
vkey,
|
||||
kCCKeySizeDES,
|
||||
NULL,
|
||||
input,
|
||||
inputSize,
|
||||
(void *)buffer,
|
||||
bufferSize,
|
||||
&movedBytes);
|
||||
if (ccStatus != kCCSuccess) {
|
||||
NSLog(@"error code %d", ccStatus);
|
||||
free(buffer);
|
||||
return nil;
|
||||
}
|
||||
NSData *encrypted = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)movedBytes];
|
||||
free(buffer);
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
- (NSData *)decrpyt:(NSData *)raw {
|
||||
const void *input = raw.bytes;
|
||||
size_t inputSize = raw.length;
|
||||
|
||||
size_t bufferSize = 1024;
|
||||
uint8_t *buffer = malloc(bufferSize * sizeof(uint8_t));
|
||||
memset((void *)buffer, 0x0, bufferSize);
|
||||
size_t movedBytes = 0;
|
||||
|
||||
const void *vkey = _key.bytes;
|
||||
|
||||
CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
|
||||
kCCAlgorithmDES,
|
||||
kCCOptionECBMode | kCCOptionPKCS7Padding,
|
||||
vkey,
|
||||
kCCKeySizeDES,
|
||||
NULL,
|
||||
input,
|
||||
inputSize,
|
||||
(void *)buffer,
|
||||
bufferSize,
|
||||
&movedBytes);
|
||||
|
||||
if (ccStatus != kCCSuccess) {
|
||||
NSLog(@"error code %d", ccStatus);
|
||||
free(buffer);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *decrypted = [NSData dataWithBytes:(const void *)buffer length:(NSUInteger)movedBytes];
|
||||
free(buffer);
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
- (instancetype)init:(NSData *)key {
|
||||
if (self = [super init]) {
|
||||
_key = key;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
40
Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.h
generated
Normal file
40
Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.h
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// QNGetAddrInfo.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/7/19.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef QNGetAddrInfo_h
|
||||
#define QNGetAddrInfo_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct qn_ips_ret {
|
||||
char *ips[1];
|
||||
} qn_ips_ret;
|
||||
|
||||
typedef qn_ips_ret *(*qn_dns_callback)(const char *host);
|
||||
|
||||
typedef void (*qn_ip_report_callback)(const char *ip, int code, int time_ms);
|
||||
|
||||
extern void qn_free_ips_ret(qn_ips_ret *ip_list);
|
||||
|
||||
extern int qn_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
extern void qn_freeaddrinfo(struct addrinfo *ai);
|
||||
|
||||
extern void qn_set_dns_callback(qn_dns_callback cb);
|
||||
|
||||
extern void qn_set_ip_report_callback(qn_ip_report_callback cb);
|
||||
|
||||
extern void qn_ip_report(const struct addrinfo *info, int code, int time_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* QNGetAddrInfo_h */
|
||||
147
Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.m
generated
Normal file
147
Pods/HappyDNS/HappyDNS/Util/QNGetAddrInfo.m
generated
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// QNGetAddrInfo.c
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/7/19.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "QNGetAddrInfo.h"
|
||||
|
||||
//fast judge domain or ip, not verify ip right.
|
||||
static int isIp(const char* domain) {
|
||||
size_t l = strlen(domain);
|
||||
if (l > 15 || l < 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const char* p = domain; p < domain + l; p++) {
|
||||
if ((*p < '0' || *p > '9') && *p != '.') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct addrinfo* addrinfo_clone(struct addrinfo* addr) {
|
||||
struct addrinfo* ai;
|
||||
ai = (struct addrinfo*)calloc(sizeof(struct addrinfo) + addr->ai_addrlen, 1);
|
||||
if (ai) {
|
||||
memcpy(ai, addr, sizeof(struct addrinfo));
|
||||
ai->ai_addr = (struct sockaddr*)(ai + 1);
|
||||
memcpy(ai->ai_addr, addr->ai_addr, addr->ai_addrlen);
|
||||
if (addr->ai_canonname) {
|
||||
ai->ai_canonname = strdup(addr->ai_canonname);
|
||||
}
|
||||
ai->ai_next = NULL;
|
||||
}
|
||||
return ai;
|
||||
}
|
||||
|
||||
static void append_addrinfo(struct addrinfo** head, struct addrinfo* addr) {
|
||||
if (*head == NULL) {
|
||||
*head = addr;
|
||||
return;
|
||||
}
|
||||
struct addrinfo* ai = *head;
|
||||
while (ai->ai_next != NULL) {
|
||||
ai = ai->ai_next;
|
||||
}
|
||||
ai->ai_next = addr;
|
||||
}
|
||||
|
||||
void qn_free_ips_ret(qn_ips_ret* ip_list) {
|
||||
if (ip_list == NULL) {
|
||||
return;
|
||||
}
|
||||
char** p = ip_list->ips;
|
||||
while (*p != NULL) {
|
||||
free(*p);
|
||||
p++;
|
||||
}
|
||||
free(ip_list);
|
||||
}
|
||||
|
||||
static qn_dns_callback dns_callback = NULL;
|
||||
int qn_getaddrinfo(const char* hostname, const char* servname, const struct addrinfo* hints, struct addrinfo** res) {
|
||||
if (dns_callback == NULL || hostname == NULL || isIp(hostname)) {
|
||||
return getaddrinfo(hostname, servname, hints, res);
|
||||
}
|
||||
|
||||
qn_ips_ret* ret = dns_callback(hostname);
|
||||
if (ret == NULL) {
|
||||
return EAI_NODATA;
|
||||
}
|
||||
if (ret->ips[0] == NULL) {
|
||||
qn_free_ips_ret(ret);
|
||||
return EAI_NODATA;
|
||||
}
|
||||
int i;
|
||||
struct addrinfo* ai = NULL;
|
||||
struct addrinfo* store = NULL;
|
||||
int r = 0;
|
||||
for (i = 0; ret->ips[i] != NULL; i++) {
|
||||
r = getaddrinfo(ret->ips[i], servname, hints, &ai);
|
||||
if (r != 0) {
|
||||
break;
|
||||
}
|
||||
struct addrinfo* temp = ai;
|
||||
ai = addrinfo_clone(ai);
|
||||
append_addrinfo(&store, ai);
|
||||
freeaddrinfo(temp);
|
||||
ai = NULL;
|
||||
}
|
||||
qn_free_ips_ret(ret);
|
||||
if (r != 0) {
|
||||
qn_freeaddrinfo(store);
|
||||
return r;
|
||||
}
|
||||
*res = store;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qn_freeaddrinfo(struct addrinfo* ai) {
|
||||
if (ai == NULL) {
|
||||
return;
|
||||
}
|
||||
struct addrinfo* next;
|
||||
do {
|
||||
next = ai->ai_next;
|
||||
if (ai->ai_canonname)
|
||||
free(ai->ai_canonname);
|
||||
/* no need to free(ai->ai_addr) */
|
||||
free(ai);
|
||||
ai = next;
|
||||
} while (ai);
|
||||
}
|
||||
|
||||
void qn_set_dns_callback(qn_dns_callback cb) {
|
||||
dns_callback = cb;
|
||||
}
|
||||
|
||||
static qn_ip_report_callback ip_report_cb = NULL;
|
||||
void qn_set_ip_report_callback(qn_ip_report_callback cb) {
|
||||
ip_report_cb = cb;
|
||||
}
|
||||
|
||||
void qn_ip_report(const struct addrinfo* info, int code, int time_ms) {
|
||||
if (ip_report_cb == NULL || info == NULL) {
|
||||
return;
|
||||
}
|
||||
char ip_str_buf[32] = {0};
|
||||
const char* c_ip;
|
||||
if (info->ai_family == AF_INET6) {
|
||||
c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in6*)(info->ai_addr))->sin6_addr, ip_str_buf, sizeof(ip_str_buf));
|
||||
} else {
|
||||
c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in*)(info->ai_addr))->sin_addr, ip_str_buf, sizeof(ip_str_buf));
|
||||
}
|
||||
if (c_ip == NULL) {
|
||||
c_ip = "";
|
||||
}
|
||||
ip_report_cb(c_ip, code, time_ms);
|
||||
}
|
||||
21
Pods/HappyDNS/HappyDNS/Util/QNHex.h
generated
Normal file
21
Pods/HappyDNS/HappyDNS/Util/QNHex.h
generated
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// QNHex.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/7/31.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
char *qn_encodeHexData(char *output_buf, const char *data, int data_size, BOOL up);
|
||||
|
||||
@interface QNHex : NSObject
|
||||
|
||||
+ (NSString *)encodeHexData:(NSData *)data;
|
||||
+ (NSString *)encodeHexString:(NSString *)str;
|
||||
|
||||
+ (NSData *)decodeHexString:(NSString *)hex;
|
||||
+ (NSString *)decodeHexToString:(NSString *)hex;
|
||||
|
||||
@end
|
||||
108
Pods/HappyDNS/HappyDNS/Util/QNHex.m
generated
Normal file
108
Pods/HappyDNS/HappyDNS/Util/QNHex.m
generated
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// QNHex.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 15/7/31.
|
||||
// Copyright (c) 2015年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNHex.h"
|
||||
|
||||
static char DIGITS_LOWER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
static char DIGITS_UPPER[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
static int hexDigit(char c) {
|
||||
int result = -1;
|
||||
if ('0' <= c && c <= '9') {
|
||||
result = c - '0';
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
result = 10 + (c - 'a');
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
result = 10 + (c - 'A');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static char *decodeHex(const char *data, int size) {
|
||||
if ((size & 0x01) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
char *output = malloc(size / 2);
|
||||
int outLimit = 0;
|
||||
for (int i = 0, j = 0; j < size; i++) {
|
||||
int f = hexDigit(data[j]);
|
||||
if (f < 0) {
|
||||
outLimit = 1;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
int f2 = hexDigit(data[j]);
|
||||
if (f2 < 0) {
|
||||
outLimit = 1;
|
||||
break;
|
||||
}
|
||||
f = (f << 4) | f2;
|
||||
j++;
|
||||
output[i] = (char)(f & 0xff);
|
||||
}
|
||||
if (outLimit) {
|
||||
free(output);
|
||||
return NULL;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
static char *encodeHexInternal(char *output_buf, const char *data, int size, char hexTable[]) {
|
||||
for (int i = 0, j = 0; i < size; i++) {
|
||||
output_buf[j++] = hexTable[((0XF0 & data[i]) >> 4) & 0X0F];
|
||||
output_buf[j++] = hexTable[((0X0F & data[i])) & 0X0F];
|
||||
}
|
||||
return output_buf;
|
||||
}
|
||||
|
||||
static char *encodeHex(const char *data, int size, char hexTable[]) {
|
||||
char *output = malloc(size * 2);
|
||||
return encodeHexInternal(output, data, size, hexTable);
|
||||
}
|
||||
|
||||
char *qn_encodeHexData(char *buff, const char *data, int data_size, BOOL up) {
|
||||
char *hexTable = DIGITS_UPPER;
|
||||
if (!up) {
|
||||
hexTable = DIGITS_LOWER;
|
||||
}
|
||||
return encodeHexInternal(buff, data, data_size, hexTable);
|
||||
}
|
||||
|
||||
@implementation QNHex
|
||||
|
||||
+ (NSString *)encodeHexData:(NSData *)data {
|
||||
char *e = encodeHex(data.bytes, (int)data.length, DIGITS_UPPER);
|
||||
NSString *str = [[NSString alloc] initWithBytes:e length:data.length * 2 encoding:NSASCIIStringEncoding];
|
||||
free(e);
|
||||
return str;
|
||||
}
|
||||
|
||||
+ (NSString *)encodeHexString:(NSString *)str {
|
||||
return [QNHex encodeHexData:[str dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
+ (NSData *)decodeHexString:(NSString *)hex {
|
||||
char *d = decodeHex(hex.UTF8String, (int)hex.length);
|
||||
if (d == NULL) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = [NSData dataWithBytes:d length:hex.length / 2];
|
||||
free(d);
|
||||
return data;
|
||||
}
|
||||
|
||||
+ (NSString *)decodeHexToString:(NSString *)hex {
|
||||
NSData *data = [QNHex decodeHexString:hex];
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
31
Pods/HappyDNS/HappyDNS/Util/QNIP.h
generated
Normal file
31
Pods/HappyDNS/HappyDNS/Util/QNIP.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// QNIPV6.h
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/5/25.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern int qn_localIp(char *buf, int buf_size);
|
||||
extern void qn_nat64(char *buf, int buf_size, uint32_t ipv4_addr);
|
||||
|
||||
@interface QNIP : NSObject
|
||||
|
||||
+ (BOOL)isV6;
|
||||
|
||||
+ (NSString *)adaptiveIp:(NSString *)ipv4;
|
||||
|
||||
+ (NSString *)local;
|
||||
|
||||
// ipv6 in url like http://[::xxx]/
|
||||
+ (NSString *)ipHost:(NSString *)ip;
|
||||
|
||||
+ (NSString *)nat64:(NSString *)ip;
|
||||
|
||||
+ (BOOL)isIpV6FullySupported;
|
||||
|
||||
+ (BOOL)mayBeIpV4:(NSString *)domain;
|
||||
|
||||
@end
|
||||
240
Pods/HappyDNS/HappyDNS/Util/QNIP.m
generated
Normal file
240
Pods/HappyDNS/HappyDNS/Util/QNIP.m
generated
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// QNIPV6.m
|
||||
// HappyDNS
|
||||
//
|
||||
// Created by bailong on 16/5/25.
|
||||
// Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <arpa/inet.h>
|
||||
#import <netdb.h>
|
||||
#import <netinet/in.h>
|
||||
#import <unistd.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#import "QNHex.h"
|
||||
#import "QNIP.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
#ifndef kQNDnsDefaultIPv4IP
|
||||
#define kQNDnsDefaultIPv4IP "114.114.114.114"
|
||||
#endif
|
||||
|
||||
#ifndef kQNDnsDefaultIPv6IP
|
||||
#define kQNDnsDefaultIPv6IP "2400:3200::1"
|
||||
#endif
|
||||
|
||||
void qn_nat64(char *buf, int buf_size, uint32_t ipv4addr) {
|
||||
bzero(buf, buf_size);
|
||||
//nat 4 to ipv6
|
||||
const char *p = (const char *)&ipv4addr;
|
||||
const char prefix[] = "64:ff9b::";
|
||||
memcpy(buf, prefix, sizeof(prefix));
|
||||
char *phex = buf + sizeof(prefix) - 1;
|
||||
qn_encodeHexData(phex, p, 2, false);
|
||||
if (*phex == '0') {
|
||||
memmove(phex, phex + 1, 3);
|
||||
phex += 3;
|
||||
} else {
|
||||
phex += 4;
|
||||
}
|
||||
*phex = ':';
|
||||
phex++;
|
||||
qn_encodeHexData(phex, p + 2, 2, false);
|
||||
if (*phex == '0') {
|
||||
memmove(phex, phex + 1, 3);
|
||||
phex[3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int qn_local_ip_internal(char *buf, int buf_size, const char *t_ip) {
|
||||
struct addrinfo hints = {0}, *ai;
|
||||
int err = 0;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
int ret = getaddrinfo(t_ip, "53", &hints, &ai);
|
||||
if (ret != 0) {
|
||||
err = errno;
|
||||
return err;
|
||||
}
|
||||
|
||||
int family = ai->ai_family;
|
||||
int sock = socket(family, ai->ai_socktype, 0);
|
||||
if (sock < 0) {
|
||||
err = errno;
|
||||
freeaddrinfo(ai);
|
||||
return err;
|
||||
}
|
||||
|
||||
//fix getaddrinfo bug in ipv4 to ipv6
|
||||
if (ai->ai_family == AF_INET6) {
|
||||
((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = htons(53);
|
||||
}
|
||||
|
||||
err = connect(sock, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
if (err < 0) {
|
||||
close(sock);
|
||||
err = errno;
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t localAddress[16] = {0};
|
||||
|
||||
socklen_t addressLength = sizeof(localAddress);
|
||||
err = getsockname(sock, (struct sockaddr *)&localAddress, &addressLength);
|
||||
close(sock);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
void *addr;
|
||||
if (family == AF_INET6) {
|
||||
addr = &((struct sockaddr_in6 *)&localAddress)->sin6_addr;
|
||||
} else {
|
||||
addr = &((struct sockaddr_in *)&localAddress)->sin_addr;
|
||||
}
|
||||
const char *ip = inet_ntop(family, addr, buf, buf_size);
|
||||
if (ip == nil) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qn_localIp(char *buf, int buf_size) {
|
||||
int ret = qn_local_ip_internal(buf, buf_size, kQNDnsDefaultIPv4IP);
|
||||
if (ret != 0) {
|
||||
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
|
||||
if (![QNIP isIpV6FullySupported]) {
|
||||
ret = qn_local_ip_internal(buf, buf_size, kQNDnsDefaultIPv6IP);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@implementation QNIP
|
||||
|
||||
+ (BOOL)isV6 {
|
||||
struct addrinfo hints = {0}, *ai;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
int ret = getaddrinfo(kQNDnsDefaultIPv4IP, "http", &hints, &ai);
|
||||
if (ret != 0) {
|
||||
return NO;
|
||||
}
|
||||
int family = ai->ai_family;
|
||||
freeaddrinfo(ai);
|
||||
BOOL result = family == AF_INET6;
|
||||
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
|
||||
if (![QNIP isIpV6FullySupported] && !ret) {
|
||||
char buf[64] = {0};
|
||||
ret = qn_local_ip_internal(buf, sizeof(buf), kQNDnsDefaultIPv6IP);
|
||||
if (strchr(buf, ':') != NULL) {
|
||||
result = YES;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
+ (NSString *)adaptiveIp:(NSString *)ipv4 {
|
||||
struct addrinfo hints = {0}, *ai;
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
int ret = getaddrinfo(ipv4.UTF8String, "http", &hints, &ai);
|
||||
if (ret != 0) {
|
||||
return nil;
|
||||
}
|
||||
int family = ai->ai_family;
|
||||
|
||||
void *addr;
|
||||
if (family == AF_INET6) {
|
||||
addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
||||
} else {
|
||||
addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
|
||||
}
|
||||
char buf[64] = {0};
|
||||
const char *ip = inet_ntop(family, addr, buf, sizeof(buf));
|
||||
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
|
||||
if (![QNIP isIpV6FullySupported] && family == AF_INET) {
|
||||
char buf2[64] = {0};
|
||||
ret = qn_local_ip_internal(buf2, sizeof(buf2), kQNDnsDefaultIPv6IP);
|
||||
if (strchr(buf2, ':') != NULL) {
|
||||
bzero(buf, sizeof(buf));
|
||||
qn_nat64(buf, sizeof(buf), *((uint32_t *)addr));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
freeaddrinfo(ai);
|
||||
return [NSString stringWithUTF8String:ip];
|
||||
}
|
||||
|
||||
+ (NSString *)local {
|
||||
char buf[64] = {0};
|
||||
int err = qn_localIp(buf, sizeof(buf));
|
||||
if (err != 0) {
|
||||
return nil;
|
||||
}
|
||||
return [NSString stringWithUTF8String:buf];
|
||||
}
|
||||
|
||||
+ (NSString *)ipHost:(NSString *)ip {
|
||||
NSRange range = [ip rangeOfString:@":"];
|
||||
if (range.location != NSNotFound) {
|
||||
return [NSString stringWithFormat:@"[%@]", ip];
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
+ (NSString *)nat64:(NSString *)ip {
|
||||
struct in_addr s = {0};
|
||||
inet_pton(AF_INET, ip.UTF8String, (void *)&s);
|
||||
char buf[64] = {0};
|
||||
qn_nat64(buf, sizeof(buf), (uint32_t)s.s_addr);
|
||||
return [NSString stringWithUTF8String:buf];
|
||||
}
|
||||
|
||||
+ (BOOL)isIpV6FullySupported {
|
||||
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
|
||||
float sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
|
||||
if (sysVersion < 9.0) {
|
||||
return NO;
|
||||
}
|
||||
#else
|
||||
NSOperatingSystemVersion sysVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
if (sysVersion.majorVersion < 10) {
|
||||
return NO;
|
||||
} else if (sysVersion.majorVersion == 10) {
|
||||
return sysVersion.minorVersion >= 11;
|
||||
}
|
||||
#endif
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)mayBeIpV4:(NSString *)domain {
|
||||
NSUInteger l = domain.length;
|
||||
if (l > 15 || l < 7) {
|
||||
return NO;
|
||||
}
|
||||
const char *str = domain.UTF8String;
|
||||
if (str == nil) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
for (const char *p = str; p < str + l; p++) {
|
||||
if ((*p < '0' || *p > '9') && *p != '.') {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
15
Pods/HappyDNS/HappyDNS/Util/QNMD5.h
generated
Normal file
15
Pods/HappyDNS/HappyDNS/Util/QNMD5.h
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// QNMD5.h
|
||||
// HappyDNS_Mac
|
||||
//
|
||||
// Created by 何昊宇 on 2018/4/25.
|
||||
// Copyright © 2018年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface QNMD5 : NSObject
|
||||
|
||||
+(NSString *)MD5:(NSString *)string;
|
||||
|
||||
@end
|
||||
28
Pods/HappyDNS/HappyDNS/Util/QNMD5.m
generated
Normal file
28
Pods/HappyDNS/HappyDNS/Util/QNMD5.m
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// QNMD5.m
|
||||
// HappyDNS_Mac
|
||||
//
|
||||
// Created by 何昊宇 on 2018/4/25.
|
||||
// Copyright © 2018年 Qiniu Cloud Storage. All rights reserved.
|
||||
//
|
||||
|
||||
#import "QNMD5.h"
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
@implementation QNMD5
|
||||
|
||||
+ (NSString *)MD5:(NSString *)string{
|
||||
|
||||
const char* input = [string UTF8String];
|
||||
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5(input, (CC_LONG)strlen(input), result);
|
||||
|
||||
NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
|
||||
for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
|
||||
[digest appendFormat:@"%02x", result[i]];
|
||||
}
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
@end
|
||||
22
Pods/HappyDNS/LICENSE
generated
Normal file
22
Pods/HappyDNS/LICENSE
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2016 Qiniu, Ltd.<sdk@qiniu.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
122
Pods/HappyDNS/README.md
generated
Normal file
122
Pods/HappyDNS/README.md
generated
Normal file
@@ -0,0 +1,122 @@
|
||||
# Happy DNS for Objective-C
|
||||
|
||||
[](http://weibo.com/qiniutek)
|
||||
[](https://github.com/qiniu/happy-dns-objc/blob/master/LICENSE)
|
||||
[](https://travis-ci.org/qiniu/happy-dns-objc)
|
||||
[](https://github.com/qiniu/happy-dns-objc/releases)
|
||||
[](https://codecov.io/gh/qiniu/happy-dns-objc)
|
||||

|
||||
|
||||
## 用途
|
||||
|
||||
调用系统底层Dns解析库,可以使用 114 等第三方 dns 解析,可以使用 Doh 协议的 Dns 解析方案,也可以集成 dnspod 等 httpdns。另外也有丰富的 hosts 域名配置。
|
||||
|
||||
## 安装
|
||||
|
||||
通过 CocoaPods
|
||||
```ruby
|
||||
pod "HappyDNS"
|
||||
```
|
||||
|
||||
通过 Swift Package Manager (Xcode 11+)
|
||||
```
|
||||
App 对接:
|
||||
File -> Swift Packages -> Add Package Dependency,输入 HappyDNS 库链接,选择相应版本即可
|
||||
库链接: https://github.com/qiniu/happy-dns-objc
|
||||
|
||||
库对接:
|
||||
let package = Package(
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/qiniu/happy-dns-objc", from: "1.0.4")
|
||||
],
|
||||
// ...
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
## 运行环境
|
||||
|
||||
|
||||
## 使用方法
|
||||
* 返回 IP 列表
|
||||
```
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:[QNResolver systemResolver]];
|
||||
[array addObject:[[QNResolver alloc] initWithAddress:@"119.29.29.29"]];
|
||||
[array addObject:[QNDohResolver resolverWithServer:@"https://dns.alidns.com/dns-query"]];
|
||||
QNDnsManager *dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]];
|
||||
NSArray <QNRecord *> *records = [dns queryRecords:@"www.qiniu.com"];
|
||||
```
|
||||
* url 请求,返回一个IP 替换URL 里的domain
|
||||
```
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:[QNResolver systemResolver]];
|
||||
[array addObject:[[QNResolver alloc] initWithAddress:@"119.29.29.29"]];
|
||||
QNDnsManager *dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]];
|
||||
NSURL *u = [[NSURL alloc] initWithString:@"rtmp://www.qiniu.com/abc?q=1"];
|
||||
NSURL *u2 = [dns queryAndReplaceWithIP:u];
|
||||
```
|
||||
* 兼容 getaddrinfo, 方便底层 C 代码接入
|
||||
```
|
||||
static QNDnsManager *dns = nil;
|
||||
dns = [[QNDnsManager alloc] init:@[ [QNResolver systemResolver] ] networkInfo:nil];
|
||||
[QNDnsManager setGetAddrInfoBlock:^NSArray *(NSString *host) {
|
||||
return [dns query:host];
|
||||
}];
|
||||
struct addrinfo hints = {0};
|
||||
struct addrinfo *ai = NULL;
|
||||
int x = qn_getaddrinfo(host, "http", &hints, &ai);
|
||||
qn_freeaddrinfo(ai); // 也可以用系统的freeaddrinfo, 代码一致,不过最好用这个
|
||||
```
|
||||
### 运行测试
|
||||
|
||||
``` bash
|
||||
$ xctool -workspace HappyDNS.xcworkspace -scheme "HappyDNS_Mac" -sdk macosx -configuration Release test -test-sdk macosx
|
||||
```
|
||||
|
||||
### 指定测试
|
||||
|
||||
可以在单元测试上修改,熟悉使用
|
||||
|
||||
``` bash
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
- 如果碰到其他编译错误,请参考 CocoaPods 的 [troubleshooting](http://guides.cocoapods.org/using/troubleshooting.html)
|
||||
- httpdns 在**ios8** 时不支持 nat64 模式下 IP 直接访问url,原因是 NSUrlConnection 不支持。无论是用http://119.29.29.29/d 还是http://[64:ff9b::771d:1d1d]/d 都不行,此时可以使用localdns方式。
|
||||
- 如果软件有国外的使用情况时,建议初始化程序采取这样的方式
|
||||
```Objective-C
|
||||
QNDnsManager *dns;
|
||||
if([QNDnsManager needHttpDns]){
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:[[QNResolver alloc] initWithAddress:@"119.29.29.29"]];
|
||||
[array addObject:[QNResolver systemResolver]];
|
||||
dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]];
|
||||
}else{
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:[QNResolver systemResolver]];
|
||||
[array addObject:[[QNResolver alloc] initWithAddress:@"114.114.114.114"]];
|
||||
dns = [[QNDnsManager alloc] init:array networkInfo:[QNNetworkInfo normal]];
|
||||
}
|
||||
```
|
||||
|
||||
## 代码贡献
|
||||
|
||||
详情参考[代码提交指南](https://github.com/qiniu/happy-dns-objc/blob/master/CONTRIBUTING.md)。
|
||||
|
||||
## 贡献记录
|
||||
|
||||
- [所有贡献者](https://github.com/qiniu/happy-dns-objc/contributors)
|
||||
|
||||
## 联系我们
|
||||
|
||||
- 如果有什么问题,可以到问答社区提问,[问答社区](http://qiniu.segmentfault.com/)
|
||||
- 如果发现了bug, 欢迎提交 [issue](https://github.com/qiniu/happy-dns-objc/issues)
|
||||
- 如果有功能需求,欢迎提交 [issue](https://github.com/qiniu/happy-dns-objc/issues)
|
||||
- 如果要提交代码,欢迎提交 pull request
|
||||
- 欢迎关注我们的[微信](http://www.qiniu.com/#weixin) [微博](http://weibo.com/qiniutek),及时获取动态信息。
|
||||
|
||||
## 代码许可
|
||||
|
||||
The MIT License (MIT).详情见 [License文件](https://github.com/qiniu/happy-dns-objc/blob/master/LICENSE).
|
||||
1
Pods/Headers/Private/HappyDNS/HappyDNS.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/HappyDNS.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/HappyDNS.h
|
||||
1
Pods/Headers/Private/HappyDNS/NSData+QNRW.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/NSData+QNRW.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/NSData+QNRW.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNAsyncUdpSocket.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNAsyncUdpSocket.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/QNAsyncUdpSocket.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDes.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDes.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/QNDes.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsDefine.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsDefine.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDnsDefine.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsError.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsError.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNDnsError.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsManager.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsManager.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNDnsManager.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsMessage.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsMessage.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDnsMessage.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsRequest.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsRequest.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDnsRequest.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsResolver.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsResolver.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDnsResolver.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsResponse.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsResponse.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDnsResponse.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnsUdpResolver.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnsUdpResolver.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDnsUdpResolver.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDnspodEnterprise.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDnspodEnterprise.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Http/QNDnspodEnterprise.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDohResolver.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDohResolver.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Dns/QNDohResolver.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNDomain.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNDomain.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNDomain.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNGetAddrInfo.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNGetAddrInfo.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/QNGetAddrInfo.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNHex.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNHex.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/QNHex.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNHijackingDetectWrapper.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNHijackingDetectWrapper.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Local/QNHijackingDetectWrapper.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNHosts.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNHosts.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Local/QNHosts.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNIP.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNIP.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/QNIP.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNLruCache.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNLruCache.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNLruCache.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNMD5.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNMD5.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Util/QNMD5.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNNetworkInfo.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNNetworkInfo.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNNetworkInfo.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNRecord.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNRecord.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNRecord.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNResolvUtil.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNResolvUtil.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Local/QNResolvUtil.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNResolver.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNResolver.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Local/QNResolver.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNResolverDelegate.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNResolverDelegate.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Common/QNResolverDelegate.h
|
||||
1
Pods/Headers/Private/HappyDNS/QNTxtResolver.h
generated
Symbolic link
1
Pods/Headers/Private/HappyDNS/QNTxtResolver.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../HappyDNS/HappyDNS/Local/QNTxtResolver.h
|
||||
1
Pods/Headers/Private/Qiniu/NSData+QNGZip.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/NSData+QNGZip.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Utils/NSData+QNGZip.h
|
||||
1
Pods/Headers/Private/Qiniu/NSData+QNMD5.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/NSData+QNMD5.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Utils/NSData+QNMD5.h
|
||||
1
Pods/Headers/Private/Qiniu/NSObject+QNSwizzle.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/NSObject+QNSwizzle.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Utils/NSObject+QNSwizzle.h
|
||||
1
Pods/Headers/Private/Qiniu/NSURLRequest+QNRequest.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/NSURLRequest+QNRequest.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/NSURLRequest+QNRequest.h
|
||||
1
Pods/Headers/Private/Qiniu/QNALAssetFile.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNALAssetFile.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Utils/QNALAssetFile.h
|
||||
1
Pods/Headers/Private/Qiniu/QNAsyncRun.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNAsyncRun.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Utils/QNAsyncRun.h
|
||||
1
Pods/Headers/Private/Qiniu/QNAutoZone.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNAutoZone.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Common/QNAutoZone.h
|
||||
1
Pods/Headers/Private/Qiniu/QNBaseUpload.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNBaseUpload.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Storage/QNBaseUpload.h
|
||||
1
Pods/Headers/Private/Qiniu/QNCFHttpClient.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNCFHttpClient.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClient.h
|
||||
1
Pods/Headers/Private/Qiniu/QNCFHttpClientInner.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNCFHttpClientInner.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpClientInner.h
|
||||
1
Pods/Headers/Private/Qiniu/QNCFHttpThreadPool.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNCFHttpThreadPool.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Http/Request/HttpClient/CFNetwork/QNCFHttpThreadPool.h
|
||||
1
Pods/Headers/Private/Qiniu/QNCache.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNCache.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Utils/QNCache.h
|
||||
1
Pods/Headers/Private/Qiniu/QNConcurrentResumeUpload.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNConcurrentResumeUpload.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Storage/QNConcurrentResumeUpload.h
|
||||
1
Pods/Headers/Private/Qiniu/QNConfig.h
generated
Symbolic link
1
Pods/Headers/Private/Qiniu/QNConfig.h
generated
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../Qiniu/QiniuSDK/Common/QNConfig.h
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user