摘要
强制网络门户(captive portal)就是手机在连接上某个WiFi的时候,自动弹出一个页面,这个页面通常可以用来配置网络、验证用户信息等,对于公司的产品可以使用此功能实现WEB运维后台。
- 强制门户原理
强制门户技术的核心是重定向,重定向的方法有多种,比如基于MAC或IP的重定向、DNS重定向、HTTP重定向、WPAD等等,当然重定向的作用范围远不止强制门户技术。无论是何种重定向,本质上是利用通信协议的机制和规则,实现特定数据流的转发
对于强制门户使用的主要是DNS重定向和HTTP重定向结合的方案,通过DNS重定向,将用户的外网访问请求指定到管理地址,然后HTTP进程接收特定的HTTP请求后,返回特定的HTTP重定向报文,客户端浏览器以重定向报文中指定的URL再次发起请求,以此将用户强制到网关的登陆页面。
图1 强制门户重定向交互流程
- DNS应用层协议
- DNS资源记录
在介绍DNS层协议之前,先了解一下DNS服务器存储的资源记录(Resource Records,RRs),一条资源记录(RR)记载着一个映射关系。每条RR通常包含如下表所示的一些信息:
表1 RR信息类型
字段 | 含义 |
NAME | 名字 |
TYPE | 类型 |
CLASS | 类 |
TTL | 生存时间 |
RDLENGTH | RDATA所占的字节数 |
RDATA | 数据 |
NAME和RDATA表示的含义根据TYPE的取值不同而不同,常见的:
-
- 若TYPE=A,则name是主机名,value是其对应的ip;
- 若TYPE=NS,则name是一个域,value是一个权威DNS服务器的主机名。该记录表示name域的域名解析将由value主机名对应的DNS服务器来做;
- 若TYPE=CNAME,则value是别名为name的主机对应的规范主机名;
- 若TYPE=MX,则value是别名为name的邮件服务器的规范主机名;
- ……
TYPE实际上还有其他类型,所有可能的type及其约定的数值表示如下:
表2 TYPE类型以及含义
TYPE | value | meaning |
A | 1 | a host address |
NS | 2 | an authoritative name server |
MD | 3 | a mail destination (Obsolete - use MX) |
MF | 4 | a mail forwarder (Obsolete - use MX) |
CNAME | 5 | the canonical name for an alias |
SOA | 6 | marks the start of a zone of authority |
MB | 7 | a mailbox domain name (EXPERIMENTAL) |
MG | 8 | a mail group member (EXPERIMENTAL) |
MR | 9 | a mail rename domain name (EXPERIMENTAL) |
NULL | 10 | a null RR (EXPERIMENTAL) |
WKS | 11 | a well known service description |
PTR | 12 | a domain name pointer |
HINFO | 13 | host information |
MINFO | 14 | mailbox or mail list information |
MX | 15 | mail exchange |
TXT | 16 | text strings |
-
- DNS整体说明
DNS请求与响应的格式是一致的,其整体分为Header、Question、Answer、Authority、Additional5部分,如下图所示:
图2 DNS协议整体结构
-
- Header部分说明
Header部分是一定有的,长度固定为12个字节;其余4部分可能有也可能没有,并且长度也不一定,这个在Header部分中有指明。Header的结构如下:
图3 Header结构
下面说明一下各个字段的含义:
- ID:占16位。该值由发出DNS请求的程序生成,DNS服务器在响应时会使用该ID,这样便于请求程序区分不同的DNS响应。
- QR:占1位。指示该消息是请求还是响应。0表示请求;1表示响应。
- OPCODE:占4位。指示请求的类型,有请求发起者设定,响应消息中复用该值。0表示标准查询;1表示反转查询;2表示服务器状态查询。3~15目前保留,以备将来使用。
- AA(Authoritative Answer,权威应答):占1位。表示响应的服务器是否是权威DNS服务器。只在响应消息中有效。
- TC(TrunCation,截断):占1位。指示消息是否因为传输大小限制而被截断。
- RD(Recursion Desired,期望递归):占1位。该值在请求消息中被设置,响应消息复用该值。如果被设置,表示希望服务器递归查询。但服务器不一定支持递归查询。
- RA(Recursion Available,递归可用性):占1位。该值在响应消息中被设置或被清除,以表明服务器是否支持递归查询。
- Z:占3位。保留备用。
- RCODE(Response code):占4位。该值在响应消息中被设置。取值及含义如下:
- 0:No error condition,没有错误条件;
- 1:Format error,请求格式有误,服务器无法解析请求;
- 2:Server failure,服务器出错。
- 3:Name Error,只在权威DNS服务器的响应中有意义,表示请求中的域名不存在。
- 4:Not Implemented,服务器不支持该请求类型。
- 5:Refused,服务器拒绝执行请求操作。
- 6~15:保留备用。
- QDCOUNT:占16位(无符号)。指明Question部分的包含的实体数量。
- ANCOUNT:占16位(无符号)。指明Answer部分的包含的RR(Resource Record)数量。
- NSCOUNT:占16位(无符号)。指明Authority部分的包含的RR(Resource Record)数量。
- ARCOUNT:占16位(无符号)。指明Additional部分的包含的RR(Resource Record)数量。
- Question部分说明
Question部分的每一个实体的格式如下图所示:
图4 Question结构
- QNAME:字节数不定,以0x00作为结束符。表示查询的主机名。注意:众所周知,主机名被"."号分割成了多段标签。在QNAME中,每段标签前面加一个数字,表示接下来标签的长度。比如:api.sina.com.cn表示成QNAME时,会在"api"前面加上一个字节0x03,"sina"前面加上一个字节0x04,"com"前面加上一个字节0x03,而"cn"前面加上一个字节0x02;
- QTYPE:占2个字节。表示RR类型,见上述RR介绍;
- QCLASS:占2个字节。表示RR分类,见上述RR介绍。
- Answer、Authority、Additional部分
Answer、Authority、Additional部分格式一致,每部分都由若干实体组成,每个实体即为一条RR,之前有过介绍,格式如下图所示:
图4 Answer&Authority&Additional结构
- NAME:长度不定,可能是真正的数据,也有可能是指针(其值表示的是真正的数据在整个数据中的字节索引数),还有可能是二者的混合(以指针结尾)。若是真正的数据,会以0x00结尾;若是指针,指针占2个字节,第一个字节的高2位为11。
- TYPE:占2个字节。表示RR的类型,如A、CNAME、NS等,见上述RR介绍;
- CLASS:占2个字节。表示RR的分类,见上述RR介绍;
- TTL:占4个字节。表示RR生命周期,即RR缓存时长,单位是秒;
- RDLENGTH:占2个字节。指定RDATA字段的字节数;
- RDATA:即上述介绍的value,含义与TYPE有关,见上述RR介绍。
- HTTP重定向
URL重定向(也称为 URL转发)是一种为页面、表单或者整个Web站点/应用提供多个URL地址的技术。HTTP对此操作有一种特殊类型的响应,称为 HTTP重定向(HTTP redirect)。
- 方案简述
在HTTP中,服务器可以通过返回一个重定向响应来进行重定向。这个重定向响应有一个以3开头的状态码,并且有一个 Location 头字段表示要重定向到的位置。
浏览器接收到这个重定向之后,会立即加载 Location中指定的URL。通常这一过程耗时极短,用户基本注意不到这个过程。
重定向过程如下图所示:
图5 HTTP重定向过程
-
- 重定向状态码及含义
表3 HTTP重定向状态码
状态码 | 状态短语 | 状态含义 |
300 | Multiple Choices | 当请求的URL对应有多个资源时(如同一个HTML的不同语言的版本),返回这个代码时,可以返回一个可选列表,这样用户可以自行选择。通过Location头字段可以自定首选内容。 |
301 | Moved Permanetly | 当前请求的资源已被移除时使用,响应的Location 头字段会提供资源现在的URL。直接使用GET方法发起新情求。 |
302 | Found | 与301类似,但客户端只应该将Location返回的URL当做临时资源来使用,将来请求时,还是用老的URL。直接使用GET方法发起新情求。 |
303 | See Other | 用于在PUT或者POST请求之后进行重定向,这样在结果页就不会再次触发重定向了。 |
304 | Not Modified | 资源未修改,表示本地缓存仍然可用。 |
305 | Use Proxy | 用来表示必须通过一个代理来访问资源,代理的位置有Location头字段给出 |
306 | Switch Proxy | 在最新版的规范中,306状态码已不再被使用。最初是指“后续请求应使用指定的代理”。 |
307 | Temporary Redirect | 与302类似,但是使用原请求方法发起新情求。 |
308 | Permanent Redirect | 与 301 类似,但是使用原请求方法发起新情求。 |
这9种状态码可以分成3大类,分别是:
- 永久重定向:301、308;
- 临时重定向:302、303、307
- 特殊重定向:300、304、305、306;
对于强制门户,使用一般都为临时重定向,下面进一步说明临时重定向处理方法以及应用场景。
表4 临时重定向使用场景
状态码 | 处理方法 | 典型应用场景 |
302 | 由于不可预见的原因该页面暂不可用。 | |
303 | GET方法不会发生变更,其他方法会变更为GET方法(消息主体丢失)。 | |
307 | 方法和消息主体都不发生变化。 | 由于不可预见的原因该页面暂不可用。当站点支持非GET方法的链接或操作的时候,该状态码优于302状态码。 |
由于我们的状态HTTP服务器仅支持GET方法,所以选用302进行HTTP重定向。
- 相关案例分析
在了解了上述强制门户的原理以及相关基础后,下面,使用Wireshark抓取路由器强制门户的实际案例。
(dns || tcp || http) && !tcp.analysis.out_of_order && !tcp.analysis.retransmission && !tcp.analysis.duplicate_ack |
其中WireShark过滤规则可以参考如下规则:
- dns || tcp || http:
- dns:显示所有DNS协议的数据包。
- tcp:显示所有TCP协议的数据包。
- http:显示所有HTTP协议的数据包。
- 逻辑操作符||表示“或”,即只要数据包属于DNS、TCP或HTTP协议之一,就会被显示出来。
- !tcp.analysis.out_of_order && !tcp.analysis.retransmission && !tcp.analysis.duplicate_ack :
- tcp.analysis.out_of_order:标识为“TCP out of order”的数据包。这些数据包表示TCP流中的数据包到达顺序与发送顺序不一致。
- tcp.analysis.retransmission:标识为“TCP Retransmission”的数据包。这些数据包表示数据包由于丢失或错误而被重新发送。
- tcp.analysis.duplicate_ack:标识为“TCP Dup ACK”的数据包。这些数据包表示接收方收到了重复的ACK(确认)数据包,通常表示之前的某个数据包没有正确接收。
- !:表示“非”或“排除”,即排除掉上述所有标记的数据包。
- 2、DNS解析
分析其DNS解析部分,可以看到路由器将客户端的DNS请求,解析为了172.31.255.254这个IP地址,后续客户端将使用此IP去打开socket。
图6 DNS解析报文
- 建立TCP连接并且进行HTTP重定向
图7 HTTP重定向报文
- 建立TCP连接
在通过DNS获取到目标IP(172.31.255.254)后,客户端将与目标IP建立TCP连接,其端口为HTTP的默认端口:80;
- HTTP请求以及重定向
建立TCP连接后,客户端请求HTTP服务,服务使用307将HTTP请求进行重定向到http://192.168.8.1/html/index.html?origin=xxx,此url为路由器的管理网站;
- 关闭TCP连接
因为重定向后的IP(192.168.1.1)与DNS解析的IP(172.31.255.254)不一致,所以客户端断开TCP连接。随后,客户端将使用重定向后的IP重新建立TCP连接;
-
- 登录管理页面
图8 登录管理界面报文
- 建立TCP连接
客户端将与重定向后的IP(192.168.1.1)建立TCP连接,其端口为HTTP的默认端口:80;
- HTTP请求与回复
建立TCP连接后,客户端使用重定向的url(/html/index.html?origin=xxx)发起HTTP请求,服务端回复管理页面的html文件;
至此,客户端WEB已成功打开管理页面,强制门户认证过程完成。
-
- 对比ESP32门户网站案例
在分析完路由器的案例后,又抓取了ESP32门户网站的相关报文。
发现两者之间存在以下差异点:
- 对于DNS请求的处理不同
- 路由器将客户端所有的DNS请求统一定向到172.31.255.254;
图9 路由器DNS请求与回复
- ESP32仅对部分域名(type A)的DNS请求返回了IP(192.168.4.1),但是对其余的DNS请求,进行了特殊的回复(Unused);
图10 ESP32DNS请求与回复
其特殊回复实现主要是将Type值设置为了0,如下图所示:
图10 ESP32回复Unused
查看DNS的标准规范DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION并未找到对Type值为0的明确定义,但在DNS的相关规范中Domain Name System (DNS) IANA Considerations找到了如下说明:
说明了RRTYPE值为0的特殊用途,即在某些特定的情况下(例如SIG(0)记录中)使用,而不应用于普通的DNS查询。虽未并未明确说明Type0可以在用于这种情况,但在此暂且进行深究,若有兴趣可以继续研读相关规范。
图11 对于Type0的相关说明
- HTTP重定向状态码不同
图12 HTTP重定位内容对比
- 路由器使用307进行重定向回复
- ESP32使用302进行重定向回复
参照上述表4对于状态码的描述,可以看到,ESP32重定位后仅支持GET方法,而路由器重定位后所支持更多的请求方法。
- HTTP重定位内容差异
- 路由器重定位时,不仅指定新资源的url:/html/index.html?origin=xxx,同时,指定了新资源的IP地址: 192.168.8.1;
- ESP32重定位时,仅指定新资源的url:/;
路由器将所有客户端的DNS请求解析到一个特定的IP地址(172.31.255.254),这是一个中间服务器,此IP不是真正的目标网站,而是一个内部IP,路由器用它来捕获所有的流量。但是,此操作需要多打开一个TCP服务器,对于资源要求较高。
-
- 正常WiFi测试
- 正常WiFi测试
图13 WIFI测试
- DNS请求
- 系统首先会进行 DNS 查询,解析 `www.msftconnecttest.com` 这个域名。由于该域名是一个 CNAME 记录,实际解析指向的是 `ncsi-geo.trafficmanager.net`。
- 系统通过 DNS 查询获得 `ncsi-geo.trafficmanager.net` 的 IP 地址
- HTTP 请求
- -在成功解析到 IP 地址后,系统会尝试通过 HTTP 协议访问 `http://www.msftconnecttest.com/connecttest.txt`。
- 这是一个简单的 HTTP GET 请求,没有复杂的参数或数据发送。请求的目标是获取一个预定义的静态文件。
- 接收响应
- 如果请求成功,服务器会返回一个 HTTP 200 OK 的状态码以及一个包含预期文本内容的响应体,通常这个文件内容是 `Microsoft Connect Test`。
- 如果能够成功接收到这个内容,系统就会判断当前网络连接能够访问互联网,并在网络状态图标上显示“已连接互联网”。
- 方案确定
- 方案总述
基于上述分析,确定最终的门户认证方案,其流程如下:
图13 强制门户流程
- 因资源限制,只能开启一个TCP服务器,所以在域名解析时仅将部分域名直接解析为最终的IP(192.168.1.1),并且,对其余的DNS请求,进行特殊回复(Unused);
- 因仅支持GET请求,所以HTTP重定义时使用302进行回复;
- 疑问点分析
若要按照上述步骤实施,要解决下面两个问题:
Q1:DNS解析时,将哪些域名解析为:192.168.1.1?
A1:在案例分析中看到路由器对所有的DNS请求都进行解析,而ESP32仅正常解析Type A记录查询,也可以实现强制门户,这是因为Type A应用于网站访问。那么,域名解析的范围是否可以进一步缩小呢?
市场上的各类设备通常会访问特定域名,用于检测互联网连接状态,为了确保强制门户跳转(Captive Portal)能够在常见的设备上生效,就需要穷举出这些域名:
表5 各设备域名表
设备类型 | 域名 |
Windows设备 | www.msftconnecttest.com connectivitycheck.gstatic.com |
联想设备 | connectivitycheck.lenovo.com |
苹果设备 | captive.apple.com www.apple.com/library/test/success.html www.apple.com |
安卓设备 | connectivitycheck.android.com clients3.google.com/generate_204 |
鸿蒙设备 | connectivitycheck.hicloud.com |
华为设备 | connectivitycheck.platform.hicloud.com |
小米设备 | www.miui.com/generate_204 connect.rom.miui.com/generate_204 |
Vivo设备 | devel.vivo.com.cn/generate_204 |
三星设备 | config.samsungcloudsolution.com/generate_204 |
OPPO设备 | connectivitycheck.oppo.com |
一加设备 | connectivitycheck.oneplus.net |
索尼设备 | connectivitycheck.sonymobile.com |
归纳一下上述表格,得到以下通用字段:
msftconnecttest、connectivitycheck、generate_204、apple
经过上述分析,确定正常解析的域名需同时满足以下两个条件:
- 条件一:DNS查询类型为Type A;
- 条件二:域名中包含通用字段;
*注意:虽然上述的字段可以包含市面常见设备,但无法保证对支持所有设备,在资源足够的情况下,不建议使用条件二进行过滤!
Q2:若TCP服务器只能打开1个socket,如何保证跳转成功率?
A2:首先分析路由器和ESP32的相关报文:
- 在成功跳转到ESP32门户网站前,设备依然保持其余3个socket连接,总共耗费了4个socket资源,才成功跳转到了门户网站;
图14 路由器socket连接状态
- 在成功跳转到ESP32门户网站前,设备依然保持其余2个socket连接,总共耗费了3个socket资源,才成功跳转到了门户网站。
虽然从表现上ESP32相对路由器少消耗1个socket资源,但是,深入分析发现,这只是因为设备DNS请求的顺序不一致导致的,因此,其现象不存在必然性。
图14 ESP32 socket连接状态
按照上面分析,要成功跳转到门户网站一般需要3-4个socket资源,但因设备资源限制(共5个socket资源,其余4个socket用作它用),仅有1个socket资源用于门户网站,所以,必须通过优化相关过程,才能实现强制门户跳转。
按照上面分析,主要可以从下面两方面进行流程优化:
优化一:提高Socket资源准确性
- 如上面A1所述,通过增加DNS解析条件,使Socket资源更精确地用于门户网站,从而提升Socket资源的使用准确性。
优化二:提高Socket资源使用率
- 缩短重定向后资源的有效时长:
- DNS重定向:当通过DNS解析将请求重定向至强制门户时,将重定向后资源的有效时长设定为5秒。这意味着在DNS缓存或TTL过期后,客户端将再次进行DNS查询,有助于快速恢复正常的网络访问。
- HTTP重定向:在需要重定向至门户页面时,使用HTTP状态码302(临时重定向),指示客户端临时访问强制门户。
- 服务器主动关闭非门户网站连接:
- 在检测到Socket连接未成功打开门户网站后,服务器将主动关闭该连接。这种措施有助于释放无效的Socket资源,避免长时间占用资源而导致其他用户无法访问门户页面。
- 通过监控Socket连接的状态和活动情况,服务器可以判断哪些连接未正确访问门户,并及时进行处理,以优化资源利用率。
这些优化措施旨在确保Socket资源被准确、高效地使用,从而提升强制门户方案的整体性能和用户体验。