Androidアプリから、独自証明書を設定しているsocket.ioサーバーへWebSocket接続をしたい

実現したいこと

下記のコードで、androidアプリからLAN内のサーバーへWebSocket接続したいのですが、Bad Requestとだけ返ってきてしまい、接続できていません。なぜ接続できないのか、解決方法を教えていただきたいです。

発生している問題・分からないこと

サーバーにはドメインは設定されておらず、同一LANからIPアドレスでアクセスしています。httpsアクセスはできるようにしていますが、証明書は独自証明書を設定しています。
network_security_configで独自証明書を信頼するよう設定も入れているつもりなのですが、接続できていません。
サーバーサイドはsocket.ioで実装されています。

以下に記載のエラーメッセージは、WebSocketListener@onFailureで表示されています。記載のコードでnewWebSocket()を実行すると、ほとんどタイムラグなくWebSocketListener@onFailureが呼ばれてエラーが出ます。

エラーメッセージ

error

1java.lang.Throwable: java.net.ProtocolException: Expected HTTP 101 response but was '400 Bad Request' 2 at com.example.talk_on_lan.common.WebSocketController.onFailure(WebSocketController.kt:343) 3 at okhttp3.internal.ws.RealWebSocket.failWebSocket(RealWebSocket.kt:592) 4 at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:173) 5 at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) 6 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 7 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644) 8 at java.lang.Thread.run(Thread.java:1012) 9Caused by: java.net.ProtocolException: Expected HTTP 101 response but was '400 Bad Request' 10 at okhttp3.internal.ws.RealWebSocket.checkUpgradeSuccess$okhttp(RealWebSocket.kt:224) 11 at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:170) 12 at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)  13 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)  14 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)  15 at java.lang.Thread.run(Thread.java:1012)  16

該当のソースコード

kotlin

1 val client = OkHttpClient.Builder()2 .retryOnConnectionFailure(true)3 .pingInterval(5, TimeUnit.SECONDS)4 .connectTimeout(10, TimeUnit.SECONDS)5 .readTimeout(30, TimeUnit.SECONDS)6 .certificatePinner(CertificatePinner.Builder().also {7 it.add(serverIp, pin)8 }.build())9 .build()10 val req = Request.Builder()11 .url("https://$serverIp:$serverPort/socket.io/?transport=polling")12 .addHeader("Upgrade", "websocket")13 .addHeader("Connection", "upgrade")14 //.addHeader("Sec-Websocket-Extensions", "permessage-deflate; client_max_window_bits")15 .addHeader("Sec-Websocket-Version", "13")16 .addHeader("Sec-Websocket-Key", UUID.randomUUID().toString().replace("-", ""))17 .addHeader("User-Agent", userAgent)18 .build()19 20 val ws = client.newWebSocket(req, this)21

試したこと・調べたこと

上記の詳細・結果

httpsでなくwssでアクセスしても変わりませんでした。

SSL無しで平文でアクセスすると、サーバーからは何もレスポンスが返ってきません。

okhttpの他にsocket.io-clientとjava.net.HttpURLConnectionで同様に接続を試してみましたが、結果は特に変わりませんでした。

HttpURLConnectionで、WebSocketでなく単純なHTTPリクエストをすると、以下のレスポンスが返ってきました。

json

1{"code":3,"message":"Bad request"}

的外れかも知れませんが、こちらのページによるとSSLハンドシェイクに問題があると取れます。しかし、network_security_config.xmlを中心にSSL周りの設定を確認したり値を変えて試行錯誤していますが、解決には至っていません。

補足

network_security_config.xmlを以下に記載します。raw/my_ca_pemとpinのSHA-256ダイジェストは同じ証明書から設定しています。cleartextTrafficPermittedはtrueにしていますが、falseにしても解決はしていません。

XML

1<?xml version="1.0" encoding="utf-8"?> 2<network-security-config> 3 <domain-config cleartextTrafficPermitted="true"> 4 <domain includeSubdomains="false">192.168.xxx.xxx</domain> 5 <trust-anchors> 6 <certificates src="@raw/my_ca_pem" /> 7 <certificates src="system" /> 8 </trust-anchors> 9 <pin-set> 10 <pin digest="SHA-256">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</pin> 11 </pin-set> 12 </domain-config> 13</network-security-config>

コメントを投稿

0 コメント