为什么 Android 的 Captive Portal 检测不会触发浏览器窗口?

Tal*_*Tal 5 webserver android http nginx

我有一个使用 nginx 托管一个简单网站的 Raspberry Pi。RPi 充当无线接入点 - 用户可以连接到其无线网络,RPi 为他们提供一个 IP(它运行 DHCP 服务器),他们可以访问该站点。

因为 RPi 实际上并不为用户提供互联网(只有这一个站点),所以我让用户更容易找到该站点。我没有知道该站点的确切 URL,而是告诉我的 dns 服务器 (dnsmasq),DHCP 服务器告诉客户端使用它来解析对我的 RPi (192.168.30.1) 的 LAN IP 的所有查询。

此时,我的 nginx 在其配置中有一个条目,内容为:

  • 如果用户请求的主机字段不是 MyRPiServer.com,则发送 302 重定向到 MyRPiServer.com
  • 如果主机是MyRPiServer.com,则服务本地网站

这很棒。

我想更进一步。当 Android 连接到无线网络时,它会尝试连接到http://connectivitycheck.gstatic.com/generate_204(或其他类似的谷歌页面之一),专门检查请求是否被重定向。如果它得到 204 代码,则假定一切正常。如果没有,则假定它位于强制门户后面,并弹出一个浏览器窗口,打开强制门户登录。

出于某种原因,当我告诉 nginx 使用 302 重定向或什至 200(带有一些文本)响应对 generate_204 页面的请求时,Android 不会弹出浏览器。

我有一个带有内置热点功能的 mikrotik 路由器,它确实让 android 使用强制门户登录(在同一个测试手机上)弹出浏览器。当我查看它发送给我的客户端的流量时,它是一个简单的 HTTP 200,带有一些文本,就像我的一样。

似乎可行的一件事是,如果我禁用 DNS 服务器将所有内容解析为 192.168.30.1,并使用 iptables 将端口 80 重定向到我的 RPi 上的 localhost。

有谁知道为什么在 Android 的 Captive Portal 检测中重定向端口 80 有效,但配置 DNS 服务器以将所有内容解析为 RPi 本地 IP 却没有?

查看此处找到的代码/sf/answers/982119351/,似乎 Android 唯一关心的是它是否可以连接到主机,以及它是否能返回 HTTP 204。就我而言,它肯定是在连接,而且肯定不会返回 204(nginx 日志显示它发送 HTTP 302 和 HTTP 200)。

我的手机运行的是 Android 8,所以我想现在链接的代码可能会有所不同。

Tal*_*Tal 3

我找到的解决方案是将我的 dnsmasq 设置为继续将所有内容解析为 192.168.30.1,但对于强制门户测试服务器有一些例外:

10.45.12.1 clients3.google.com
10.45.12.1 clients.l.google.com
10.45.12.1 connectivitycheck.android.com
10.45.12.1 connectivitycheck.gstatic.com
10.45.12.1 play.googleapis.com
Run Code Online (Sandbox Code Playgroud)

基本上,如果有任何尝试使用我们的 DNS 服务器解析上述域,他们会得到 10.45.12.1 的回复。

10.45.12.1是一个随机IP,不属于任何东西。它不必是 192.168.30.1。

域列表来自这里

完成此操作后,只要您连接到 RPi 的 WiFi,它就会弹出显示我的站点的浏览器页面。

这是一个解决方案,但并不能真正回答为什么会发生这种情况。如果有人能解释一下,我将不胜感激。

编辑:

使用此解决方案,如果我多次连接和断开设备上的 WiFi,Android 有时会弹出登录页面,有时则不会。对于任何做类似事情的人,最后,为了更好的解决方案,我选择了这个:

  • 让 DNSmasq 将所有内容解析为 10.45.12.1(或 192.168.30.0/24 子网之外的任何内容)
    • 它必须位于 192.168.30.0/24 子网(或任何 LAN 子网)之外,否则客户端将尝试使用 ARP 来找出给定设备的 MAC 地址,并且会失败,因为该设备实际上并不存在
  • 让 iptables 将来自 wifi 接口的端口 80 转发到本地主机

这适用于 Android、OS X 和 Windows。我没有 iOS 设备来测试这个。据此 iOS 设备可能需要一些额外的工作。

我仍然很好奇为什么这是必要的,以及为什么将所有内容解析为 192.168.30.1 最初不起作用。