美文网首页
iOS HTTPDNS集成,结合AFNetwork进行“ip直连

iOS HTTPDNS集成,结合AFNetwork进行“ip直连

作者: Waynee | 来源:发表于2020-12-03 17:26 被阅读0次

            本期是通过NSURLProtocol拦截的方式替换ip,包括SNI的处理。后期有时间会有一章通过hook网络框架AFN的方式,这种方式也无需改变AFN源码,包括在HTTPS证书校验的过程。而本文主要针对HTTPS协议进行说明,HTTP协议没有SSL/TLS的证书验证的过程,处理起来比较简单,也无需用到CFNetwork,所以暂时不做讲解。还有一篇结合SDWebImage对HTTP协议进行"ip直连"的文章。无论是HTTP还是HTTPS都可结合AFNetwork和SDWebImage进行"ip直连",其中原理都是相通的。若有不足或误区,盼请指正。

            大概说一下本章内容:本文对HTTPDNS做一个较为详细的讲解,在看本文之前,您需要对系统偏底层的CFNetwork网络框架有一个比较基础的认知。整体总结为以下几点。

    一、什么是HTTPDNS?

            首先,DNS解析的目的就是通过某个域名:host(www.xxx.com)找到ip地址(111.111.1.1)。对于HTTPDNS的含义,用通俗简单一点语言解释。就是跳过运营商的DNS解析,通过ip地址直接精准对目标服务器进行连接。可避免被劫持,并大大缩短DNS解析时间,这也是对网络请求的一个重要优化环节(DNS优化)。

            我们都知道一般的request发出去之后的第一步就是对请求域名进行解析,而一般情况下我们的解析都是走运营商的LocalDNS,首先LocalDNS会对请求过的数据做缓存,因为缓存的时效性,我们想拿到最新最准确的数据时就会受限。其次,在这个DNS解析的过程中容易被外界劫持,注入一些未知的内容(像广告一类)后返回,甚至返回一个全新的ip给用户,可能危及到用户的个人隐私。而HTTPDNS是让用户绕过LocalDNS,在发送请求之前在本地就把host换成ip,直接对准目标服务器,这样就无需去问运营商服务器索要ip了,本来耗时不短的DNS的解析过程耗已在本地客户端完成了,所以DNS解析的时间就大大缩短了。   

            至于怎么拿到host对应的ip呢,因为客户端没法拿到当前host对应的最优ip(比如根据发送请求的地域不同等原因,对应的最优ip也可能不同),所以最好不要写死在客户端,而是通过外界拿到。两种方案:1、服务器直接下发,此种情况也是比较复杂,因为涉及的很多容灾的处理,比如在ip链接失败的时候,需要用LocalDNS做兜底,并向服务器上传错误日志,询问是否需要更新本地ip集合等等一系列复杂的操作。2、通过三方拿到,比如DNSPOD,阿里等。个人建议选择支持预处理的三方,在启动app的时候,预先拿到需要的ip集合,比如阿里。


    二、结合AFNetwork的普通网络请,通过NSURLProtocol对网络进行拦截,然后进行"ip直连"。

            此文主要通过NSURLProtocol拦截请求的方式进行“ip直连”,以及post请求时,body“丢失”问题处理,SNI场景处理,利用CFNetwork对SNI的处理。先简单介绍一下NSURLProtocol,NSURLProtocol是苹果提供给开发者们专门用来劫持网络请求的一个抽象类,所以一般用到的时候选择用继承NSURLProtocol的方式,本文中的WYCustomURLProtocol就只这样一个子类。先了解几个重要的api:       

    1、+ (BOOL)canInitWithRequest:(NSURLRequest *)request;// 通过协议或是域名判断哪些域名的请求需要拦截的就返YES,反之返NO。   

    2、+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;  // 上面方法的返YES时,会走到这个方法,你可以直接返回request,也可以重定向一个request返回。

    3、- (void)startLoading;// 重定向的request就是从此发出去的

    4、- (void)stopLoading; //  当cancel请求的时候,会调用此方法。

    接下来就开始附上code了,要用UrlProtocol之前需要对之进行注册。

    第1步、在初始化AFHTTPSessionManager的时候,对其进行注册:如图 1

    图 1

    第2步、若你使用到了YTK框架,那么可以这样初始化,此处为了便于理解所以引用了YTK,实际操作的时候,建议对外提供一个注册接口,不要直接用此种直接依赖TYK的方式,以免污染HTTPDNS部分。 图 2

    图 2

    第3步、对于要过滤拦截的域名需在此方法判断 图 3

    图 3

    第4步、请求ip替换host的过程,并给header添加host, 如图 4。此处只要能正确替换,大家可以各显神通。

    图 4

    其中的wy_bodyForPost目的是为了取回body,方法体如图 5 

    图 5

            此处需要说明一下,通过NSURLProtocol拦截的post请求的body并非真的丢失了,只是body数据在URL loading system中到达这里之前就已被转成stream了。可以在request.HTTPBodyStream中解析它。

    第5步、利用CFNetwork重新构建C语言的request,并发送。如图 6和 图7

    图 6 图 7

    三、SNI场景。

            什么是SNI场景呢,SNI全称 Server Name Indication,是TLS的扩展。我们知道一个服务器可能对应了多个域名的情况,客户端与服务端在建立HTTPS连接的过程中要进行SSL/TLS握手。整个握手过程步骤分5步:

    1、客户端发起握手请求,携带随机数、支持算法列表等参数。

    2、服务端收到请求,选择合适的算法,下发公钥证书和随机数。

    3、客户端对服务端证书进行校验,并发送随机数信息,该信息使用公钥加密。

    4、服务端通过私钥获取随机数信息。

    5、双方根据以上交互的信息生成session ticket,用作该连接后续数据传输的加密密钥。

    而握手失败就发生在第3步,客户端验证后端给的证书过程如下:

    1、客户端用本地的根证书解开证书链,确认服务端下发的证书是由可信任机构颁发。

    2、客户端检查证书的domain域和扩展域,验证是否包含本次请求的host。

    若是在握手过程中客户端要是没有指定需要访问的目标域名,这就会导致一个问题:如果一台服务机对应了多个域名,每个域名对应的证书也不一样,那服务端也不知道该返回给客户端哪一套证书进行校验,导致第3步的校验失败,以至握手失败。但若是我们指定该SSL/TLS的目标域名,那服务端就知道该返回那一套证书了,即可通过证书验证,握手成功。

    那么如何指定目标域名呢?我们可以为SNI扩展字段添加一个host。而iOS的上层网络库NSURLConnection/NSURLSession没有提供对SNI字段进行配置的接口,所以要用到Socket层级的底层网络库CFNetwork,对SNI字段进行配置。如图 8

    图 8

    补充:1、为什么要在SNI的扩展里面添加传host,我不是在header传了host了吗?此处做一个简要说明:由于HTTP的host字段在header中。而SSL/TLS的握手以及证书验证都是在HTTP开始之前,所以header里面的host对于如何判断选取证书是没有关系的。这个时候,SSL/TLS协议的HELLO中增加了一个server name字段(SNI扩展字段),让HTTP的客户端可以提前设置host,从而使服务端在SSL/TLS的握手阶段可以选择正确的证书。在SSL/TLS握手过程中,若不是SNI的情况,意味着服务器只对应了一个域名,一套证书,所以可以直接返回即为正确的证书,这也是为什么不是SNI的情况下无需配置SNI的原因。前面我们说了SNI呢是一对多的情况,在拿不到host的时候不知道返回哪一套证书,就会返回默认的一套或不返回,这个时候我们就需要在配置SNI了,添加server name字段,对应的value即为host值。(比如:若是你需要通过HTTPS访问CDN节点资源,而CDN的节点往往服务了多个域名,所以需要通过SNI指定具体的域名证书进行通信。)

    四、证书校验

            在证书校验的过程中解决了SNI的问题之后呢,服务端会返回给客户端一个与请求域名相匹配的证书,在客户端验证的时候若是默认取的请求地址中的host,而此时默认host早被我们换成了ip地址了,与证书是不匹配的,所以我们需要将header中的host取出进行证书验证。数据处理过程如图9 ;证书验证过程如图 10,一般SecTrustResultType的值为kSecTrustResultProceed或kSecTrustResultUnspecified表明验证通过。

    图 9 图 10

    下面主要是一些读取数据过程中对数据的处理,细节就不多说了,基本都是更CFNetwork相关部分。 如图 11

    图 11

    相关文章

      网友评论

          本文标题:iOS HTTPDNS集成,结合AFNetwork进行“ip直连

          本文链接:https://www.haomeiwen.com/subject/tewaiktx.html