ちょっと話題の記事

SNIの動作確認にはcURLのresolvオプションが便利

2018.01.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。皆さん既知かもしれないのですが、cURLの--resolvオプションがとても便利だったので紹介させてください!

hostsファイル代わりに使える--resolvオプション

様々なWebページやWeb APIの動作確認で活躍するCLIのHTTPクライアント、cURL。要件に応じて様々なオプションを駆使していると思います。例えば複数のコンテンツをホストするバーチャルホストを検証するためにはHostヘッダをリクエストに指定します。AWSのCloudFrontにカスタムドメイン(CNAMEs)を設定しているときの例が以下です。

$ curl --hearder 'Host:example.com' https:///XXXXXX.cloudfront.net/

HTTPであればこれで事足りることが多いのですが、HTTPSでSNI(Server Name Indication)を設定している場合はTLSハンドシェイクの段階でホスト名を指定しなければならないため、Hostヘッダでは対応できません。これまで私はOSのhostsファイルを都度編集していたのですが、消し忘れてしまって後日トラブルになることがしばしばありました。--resolvオプションを利用することで、cURLのプログラム内部で一時的にhostsエントリーを追加できるので、hostsファイルの編集よりも手軽にSNIが検証できるわけです。

CloudFrontで試すのであれば、以下のような手順になります。

1. CloudFrontのIPアドレスを調べる

hostnslookupコマンドでCloudFrontのエッジサーバーのIPアドレスを確認します。

$ host XXXXXX.cloudfront.net
XXXXXX.cloudfront.net has address XX.XX.XX.123
XXXXXX.cloudfront.net has address XX.XX.XX.32
XXXXXX.cloudfront.net has address XX.XX.XX.65
XXXXXX.cloudfront.net has address XX.XX.XX.3
XXXXXX.cloudfront.net has address XX.XX.XX.67
XXXXXX.cloudfront.net has address XX.XX.XX.13
XXXXXX.cloudfront.net has address XX.XX.XX.233
XXXXXX.cloudfront.net has address XX.XX.XX.165
  :(略)

2. どれか一つを選んでresolvオプションにセット

どれでもいいので、一つ選んで--resolvオプションに指定しましょう。オプションはホスト名:ポート番号:IPアドレスの形式なので、ポート番号はアクセスする環境に合わせましょう。CloudFrontのHTTPSであれば443です。

$ curl -v https://example.com/ --resolv example.com:443:XX.XX.XX.123
* Added example.com:443:XX.XX.XX.123 to DNS cache
* Hostname example.com was found in DNS cache
*   Trying XX.XX.XX.123...
* TCP_NODELAY set
* Connected to example.com (XX.XX.XX.123) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /usr/local/etc/openssl/cert.pem
  CApath: /usr/local/etc/openssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=example.com
*  start date: Jan 29 00:00:00 2018 GMT
*  expire date: Feb 28 12:00:00 2019 GMT
*  subjectAltName: host "example.com" matched cert's "example.com"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fd811800000)
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/7.53.1
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 301
< content-length: 0
< location: https://www.example.com/
< date: Tue, 30 Jan 2018 03:26:05 GMT
< server: AmazonS3
< age: 2047
< x-cache: Hit from cloudfront
< via: 1.1 9ea5ef5a30fe6e521c9d0059b4857565.cloudfront.net (CloudFront)
< x-amz-cf-id: CqoxdU33FmZSrgehsVqn3ov-VqL6jU6RiL0lbEAFcfmG2GcZ19ViDQ==
<
* Connection #0 to host example.com left intact
$

SNIが正しく動作していることを確認できました!

まとめ

cURLのresolvオプションでSNIの動作確認を行う例をご紹介しました。SNI以外にも応用範囲はいろいろありそうなので、引き続き使っていきたいと思います。

参考URL