Captive Portal
概述
在校园、机场、酒店、银行、咖啡店、肯德基、麦当劳等场所连接 WiFi 时,你发现不用输入WiFi 的密码,而是弹出一个网页。有的需要你输入手机号并点击获取验证码,并将通过短信获取的验证码输入,你就可以正常上网了。有的需要你输入正确的账号和密码并点击登录,然后你也可以上网。
那么问题来了,为什么我在家里连接 WiFi 时,并没有弹出所谓的网页呢?经过我在浏览器的疯狂搜索和浏览,原来使用一种叫做 “Captive Portal” 的技术实现。
captive portal
captive portal(中文称之为 强制门户)是一种通过 Web 浏览器访问的网页,在授予新连接的 Wi-Fi 或有线网络用户更广泛的网络资源访问权限之前,会向他们显示该网页。强制门户通常用于显示着陆页或登录页面,该页面可能要求身份验证、付款、接受最终用户许可协议可接受使用政策、完成调查或提供主机和用户都同意遵守的其他有效凭证。强制门户广泛用于各种移动和步行宽带服务,包括有线和商业提供的 Wi-Fi 和家庭热点。强制门户还可用于提供对企业或住宅有线网络的访问,例如公寓、酒店房间和商务中心。
实现原理
自动弹出Captive Portal认证页面实现原理:终端(手机、平板、电脑等设备)连接到WiFi后(一般该WiFi加密方式为OPEN),主动发出HTTP的探测请求报文,检测目的地址是否可达,以及回应的内容是否符合预期,以此来判断接入的网络是否需要进行Captive Portal认证。终端探测的目标URL一般是固定的网址,各终端或APP应用存在差异。如果目标URL不可达或回应内容不符合预期,那么终端会调用浏览器再次发出HTTP请求,路由器拦截到此请求进行重定向,实现自动弹出Captive Portal认证页面的功能。
某些终端无法自动弹出页面的原因:
- 终端不会主动发出探测请求报文。
- 终端可以发出一次探测请求报文,但是由于某些安装的APP影响导致终端无法调用浏览器再次发出请求,无法自动弹出页面。
- 大部分安卓手机,自动弹portal功能,依赖用户手动点击ssid界面进行触发。
不同平台对应的测试固定网址如下:
Platform | Test URL | Expected response |
---|---|---|
Apple (MacOS/IOS Family) | http://captive.apple.com/hotspot-detect.html | “Success” (plain text) |
Google (Android/ChromeOS) | http://connectivitycheck.gstatic.com/generate_204 | HTTP status code 204 with an empty body |
Windows | http://www.msftconnecttest.com/connecttest.txt | “Microsoft Connect Test” (plain text) |
NetworkManager (GNOME) | http://nmcheck.gnome.org/check_network_status.txt | “NetworkManager is online” (plain text) |
NetworkManager (KDE Plasma) | http://networkcheck.kde.org/ | “OK” (plain text) |
实现方式
captive portal的实现方式:
- DNS拦截:将所有 DNS 请求指向自己的 portal 地址
- HTTP重定向:直接劫持 HTTP/HTTPS 流量,响应自己的页面
注意:仅网关实现了Captive Portal还不够,还不能自动弹出认证页面。需要操作系统支持才能实现在网络连接后主动弹出认证页面的功能。
抓包
今天(2024-11-17)上午我连接上了图书馆的WiFi(ssid=reader),在Ubuntu系统消息中心上弹出了Web认证消息,点击后就可以跳转到网页。此时我的WifI图标还是带问号,但我输入正确的账号和密码,就成功跳转到图书馆的官网主页,同时WiFI图标的问号消失。
我使用 wireshark 把这个过程的数据包都抓下来了。当我点击 reader WiFi网络时,此时我其实已经连接上了 reader WiFi网络,我的IP地址是 10.5.243.105
,只是无法接入互联网。在wireshark 中出现了很多 mDNS 数据包,按照正常的步骤,Ubuntu 应该会尝试去访问固定的URL,那么首先要进行DNS解析,所有先把 DNS 数据包过滤出来。
Ubuntu 会发出 DNS 数据包,这个数据包的作用是:请求本地网关帮我解析域名 connectivity-check.ubuntu.com
,如果本地网关(网络IP是 10.5.9.9
)也不知道,接着报数据包转发给上一级 DNS 服务器。可是从抓包结果来看,本地网络显然是知道该域名对应的IP地址的。
Ubuntu 拿到了域名 connectivity-check.ubuntu.com
的IP地址,接着就会发出 HTTP 请求,URL是 http:connectivity-check.ubuntu.com:80
,所有我在 wireshark 中把 HTTP 数据包过滤出来。
HTTP 请求成功了,看一下 HTTP 应答的内容是什么?这时候有意思的地方来了,HTTP 应答报文为如下部分:
1 | Frame 662: 562 bytes on wire (4496 bits), 562 bytes captured (4496 bits) on interface wlp1s0, id 0 |
而上述内容中的URL就是Web认证网页,用户只要在Ubuntu的消息中心点击WiFi认证消息,就会向这个URL发送HTTP请求,然后出现WiFI认证页面。
疑问
1、如果我不想在Ubuntu开启网络检测,该如何设置?
其实在Ubuntu 22.04 中,网络检测是默认开启的,当我们连接到一个有限网络或无线网络时,Ubuntu 会尝试去访问固定的URL来判断是否可以访问互联网。