sslh にはSNI機能があった
nginx で捌いても良いんですが、sslhはnginxより設定がシンプルだ。
443ポートを直接リッスンするならsslhでリッスンして各種ポートに透過プロキシしたほうが再利用性が高くて良い。
443 ポートで、SNIで接続先を選定
特定のホスト名のときだけ別のnginxへつなぎに行く。
protocols: ( { name: "ssh"; service: "ssh"; host: "192.168.2.5"; port: "22"; fork: true; }, { name: "tls"; alpn_protocols: [ "h2", "http/1.1", "spdy/1", "spdy/2", "spdy/3" ]; host: "192.168.100.2"; port: "443"; sni_hostnames: [ "example.tld", "example.com", ]; log_level: 0; tfo_ok: true }, { name: "tls"; alpn_protocols : [ "h2", "http/1.1", "spdy/1", "spdy/2", "spdy/3" ]; host: "192.168.100.5"; port: "443"; log_level: 0; tfo_ok: true },
起動してみる。
sslh -f -F /root/sslh.conf --listen 127.0.0.1:443
テスト
curl -v --resolve example.tld:443:127.0.0.1 https://example.tld/ # 200 ok from 100.2 curl -v --resolve example.com:443:127.0.0.1 https://example.com/ # 200 ok from 100.2 curl -v --resolve example.net:443:127.0.0.1 https://example.net/ # from 100.5
APLN とSNI
ALPNをサポートするかしないかでSNIの振り分けが変わってくる
次のようなALPN付きの条件を書いたら、SNIより先にALPNで仕分けられる
{ name: "tls"; alpn_protocols: [ "h2", "http/1.1", "spdy/1", "spdy/2", "spdy/3" ]; host: "192.168.100.2"; port: "443"; sni_hostnames: ["nginx.lan"] },
ALPNを条件にした振り分けの接続チェック
openssl s_client --connect router.lan:443 -alpn h2 --servername nginx.lan < /dev/null
openssl に -alpn
を条件に入れて、接続をチェックする。このとき、SNIは--servername
で指定している。
ALPN未指定の設定
{ name: "tls"; # alpn_protocols: なし host: "192.168.100.4"; port: "443"; sni_hostnames: ["nginx2.lan"] },
上記のように、ALPNを未指定で残す設定で書いたとき。
以下のように接続をチェックする
openssl s_client --connect router.lan:443 --servername nginx2.lan < /dev/null
SSLHではALPNがサポートされていて、ALPNつけることで絞り込みができるし、Nginxなどが対応しているのでつけてもつけなくても、ほとんど影響がない。まれにALPN非対応なWebサーバーがあったりするとこの条件を意識しないといけない。
また、curlの場合 --no-alpn
を使うことでALPNの有無でSSLHの反応が変わることがわかる。
curl -vs --http2 https://t.co > /dev/null curl -vs --no-alpn https://t.co curl -vs --no-alpn --http1.1 https://t.co > /dev/null
docker サーバーを分離できる。
docker マシンが重くなってきたので、nginxと別マシンに移動させようと思ったけど、ルーターで直接443をリッスンして振り分けることができて、レイヤ7のルーターとして動作するの便利だ。
nginxで書いても良いんだけど。nginxを入れるほどでもないし、nginxでopenvpn/ipsec/sshをマッピングするのが面倒だったので、sslhを使うことにした
sslhのコマンド引数にはない。
sslh の「設定ファイル」を書く必要があり、コマンド引数ではALPN/SNIを指定できないのが注意。
443 ポート制限に負けない。
TCP/443ポート以外の通信を「不正」とパケット破棄されるような「接続サービス」をインターネット接続と呼んで欲しくない。
UDP/443ポートまで制限するのは流石にないと思ってたけど、最近、とある旅館で遭遇したのでとても恐ろしい。HTTP/3すら否定された。
2023-05-24
SNIとALPNについて追記