私はnginxを使って簡単なウェブサイトをホストするRaspberry Piを持っています。 RPiはワイヤレスアクセスポイントとして機能します。ユーザーはワイヤレスネットワークに接続でき、RPiはIP(DHCPサーバーを実行)を提供してからサイトにアクセスできます。
RPiは実際にユーザーにインターネットを提供していないので(このサイトは1つだけです)、ユーザーがサイトを見つけやすくしました。サイトの正確なURLはわかりませんが、代わりに私のRPi(192.168.30.1)のLAN IPに対するすべてのクエリを解決するために使用するDNSサーバー(dnsmasq)をクライアントに通知するようにDHCPサーバーに指示します。
この時点で、nginx設定には次のエントリがあります。
- ユーザーが要求したホストフィールドがMyRPiServer.comでない場合、302リダイレクトはMyRPiServer.comに送信されます。
- ホストがMyRPiServer.comの場合は、ローカルWebサイトを提供します。
これは素晴らしい作品です。
私はさらに一歩進みたいです。 Androidがワイヤレスネットワークに接続したら、次のデバイスに接続しようとします。http://connectivitycheck.gstatic.com/generate_204(または他の同様のGoogleページの1つ)リクエストがリダイレクトされていることを具体的に確認してください。 204コードを受け取ったら、すべてが正常であるとします。それ以外の場合は、依存ポータルの背後にあると見なされ、依存ポータルログインを開くブラウザウィンドウがポップアップ表示されます。
何らかの理由でnginxに302リダイレクトまたは200(一部のテキストを含む)を使用してgenerate_204ページのリクエストに応答するように指示すると、Androidはブラウザをポップアップしません。
私はホットスポット機能を備えたmikrotikルーターを持っており、Androidがブラウザをポップアップし、同じテスト電話でキャプティブポータルを使用してログインできるようにします。私のクライアントに送信されるトラフィックを見ると、私のようなテキストを含む単純なHTTP 200です。
動作しているように見える方法の1つは、DNSサーバーを無効にしてすべてを192.168.30.1に解決し、iptablesを使用してポート80をRPiのlocalhostにリダイレクトすることです。
AndroidのCaptive Portalディスカバリーでポート80をリダイレクトすると機能しますが、RPiローカルIPですべてを確認するようにDNSサーバーを構成すると、機能しない理由を知っていますか?
ここで見つけたコードを確認してください。https://stackoverflow.com/a/14030276/4258196、Androidが興味を持っている唯一のことは、ホストに接続できるかどうかとHTTP 204を返すかどうかです。私の場合、私は間違いなく接続されており、間違いなく204バックを受信しません(nginxログにHTTP 302とHTTP 200を送信することが示されています)。
私の携帯電話はAndroid 8を実行しているので、リンクされたコードは今では異なる可能性があると思います。
答え1
私が見つけた解決策は、キャプティブポータルテストサーバーのいくつかの例外を除いて、すべてを192.168.30.1で解決し続けるようにdnsmasqを設定することでした。
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
デフォルトでは、誰もが当社の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がWi-Fiインターフェイスからlocalhostにポート80を転送できるようにする
これはAndroid、OS X、Windowsで動作します。これをテストするiOSデバイスはありません。 ~によるとこれ、iOSデバイスにはいくつかの追加作業が必要な場合があります。
これがなぜ必要なのか、192.168.30.1のすべてを解決することが最初はうまくいかなかった理由はまだ疑問に思います。
答え2
私はこれを理解しようとして多くの時間を費やして、ついにやった。ここでコードを見ることができますhttps://github.com/tretos53/Captive-Portal
これは、認定IPを指すドメイン、iptables、およびnginxリダイレクトの組み合わせです。
答え3
これにはいくつかの理由があり、特定のハードウェア携帯電話メーカーによっても発生する可能性があります。現在、デバイスIPを使用してすべてのDNSクエリに応答するためにMongoose OS用に構築されたCaptive Portalライブラリがあり、200テキスト応答が必要と思われるSamsungデバイス以外のデバイスには問題ありません。
ライブラリスタックは次のとおりです。 https://github.com/tripflex/captive-portal-wifi-stack
具体的には、私が使用したエンドポイントの詳細、および追加情報でこれを処理する方法の詳細とともに、依存ポータルの処理は次のとおりです。
https://github.com/tripflex/captive-portal
私がSamsungデバイスで使用するソリューションの1つは、結果のHTMLファイルで200を返すメタリフレッシュタグを使用することです。
https://github.com/tripflex/captive-portal#cportalredirect_file-setting
<html>
<head>
<title>Redirecting to Captive Portal</title>
<meta http-equiv='refresh' content='0; url=PORTAL_URL'>
</head>
<body>
<p>Please wait, refreshing. If page does not refresh, click <a href='PORTAL_URL'>here</a> to login.</p>
</body>
</html>
ただし、実際に最も重要なことは、特定のデバイスごとにエンドポイント処理を設定することです。
https://github.com/tripflex/captive-portal#known-endpoints
/mobile/status.php
Android 8.0(Samsung s9+)/generate_204
機械的人造人間/gen_204
機械的人造人間/ncsi.txt
Windows/hotspot-detect.html
iOS/OSX/hotspotdetect.html
iOS/OSX/library/test/success.html
iOSシステム/success.txt
OSX/kindle-wifi/wifiredirect.html
リクエストに応じてKindle用com.android.captiveportalloginを使用してください。/kindle-wifi/wifistub.html
キャプティブポータルログインウィンドウを要求する前にKindleを使用してください(検出のために?)