これはSecHack365 修了生 Advent Calendar 2019の24日目記事です。
これは何
なんで俺はクリスマスイブにこんなこと書いてるんだろうか
CloudflareのHTTP/3ライブラリ QuicheはRustで書かれているツールです。
この前nginxで利用できるパッチを提供してくれて、これを利用することでnginxをHTTP/3対応させることができます。
mac向けにbuildするやり方がちょっとめんどくさかったので、本稿はそのことに言及しつつ動かしていくところまでやってみる。
なお、mac向けではなくジェネリックにインストールする方法は https://github.com/cloudflare/quiche/tree/master/extras/nginx に書いていたり、すでに記事にしている人がいるので合わせて見てください。
build
rustのインストールを先にしておく。
curl https://sh.rustup.rs -sSf | sh source $HOME/.cargo/env
clangのバージョンは以下の通りです。
❯❯❯ clang -v Apple clang version 11.0.0 (clang-1100.0.33.16) Target: x86_64-apple-darwin19.2.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin
nginxを持ってきてquicheを持ってくる
curl -O https://nginx.org/download/nginx-1.16.1.tar.gz tar xzvf nginx-1.16.1.tar.gz git clone --recursive https://github.com/cloudflare/quiche
記事を書いてる際に一点macos特有の問題がfixされたので一応紹介しておくと、macosではcdylibをフラグから削除しておく必要があったのですがそれは解決されました。気になる人は以下のissueを見てください。 https://github.com/cloudflare/quiche/issues/238
ということでissueに感謝しつつ、このままパッチを当て、configureをします。
cd nginx-1.16.1 patch -p01 < ../quiche/extras/nginx/nginx-1.16.patch ./configure \ --prefix=$PWD \ --build="quiche-$(git --git-dir=../quiche/.git rev-parse --short HEAD)" \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_v3_module \ --with-openssl=../quiche/deps/boringssl \ --with-quiche=../quiche
これで生成されたmakefileには欠点があり、
生成されたところのパスはobjs/Makefile
だが、nginxのコードで初期化してないところがあってそれを無視するためにclangのオプションの -Wconditional-uninitialized
を削除する必要があります。
また、最後にリンクをするところでバグるのでLINK = $(CC) -framework Security -framework Foundation
に書き換えてmacos側で利用されてるセキュリティ周りの標準ライブラリを入れる必要もあります。
よくわからないと思うのでとりあえず該当の先頭5行を示します.これになるようにobjs/Makefileを書き換えましょう。
CC = cc CFLAGS = -pipe -O -Wall -Wextra -Wpointer-arith -Wno-unused-parameter -Wno-deprecated-declarations -Werror -g CPP = cc -E LINK = $(CC) -framework Security -framework Foundation
fixをしたら以下のコマンドを入力しましょう。
make
objsに nginx
ができていれば完成です。
オレオレ証明書作り
opensslが入ってることが前提です
~/W/a/nginx-1.16.1 ❯❯❯ openssl version OpenSSL 1.0.2s 28 May 2019
入っていない人や古い人は以下のよう感じで雑に入れてください。
brew install openssl brew link openssl --force openssl version
では雑に鍵を作りましょう。実験なので、コマンド叩いたら雑にenter key叩きまくるだけで大丈夫です。
~/W/a/n/conf ❯❯❯ openssl genrsa 2048 > server.key Generating RSA private key, 2048 bit long modulus ...................................................................................................................................................................+++++ ............................................................+++++ unable to write 'random state' e is 65537 (0x10001) ~/W/a/n/conf ❯❯❯ openssl req -new -key server.key > server.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:localhost Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: ~/W/a/n/conf ❯❯❯ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt Signature ok subject=/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=localhost Getting Private key unable to write 'random state' ~/W/a/n/conf ❯❯❯ ls fastcgi.conf koi-utf mime.types scgi_params server.csr uwsgi_params fastcgi_params koi-win nginx.conf server.crt server.key win-utf
これで server.pem
, server.key
という名前のファイルができました。
コンフィグ
とりあえず以下のコンフィグをnginx-1.16.1/conf
に書いてください。pathのところは良しなにしてください。
events { worker_connections 1024; } http { server { # Enable QUIC and HTTP/3. listen 4443 quic reuseport; ssl_certificate path/server.crt; ssl_certificate_key path/server.key; # Enable all TLS versions (TLSv1.3 is required for QUIC). ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; location / { root html; index index.html index.htm; } } }
動かしてみる
まず,errorfileを作ります。
~/W/a/nginx-1.16.1 ❯❯❯ pwd ~/nginx-1.16.1 mkdir logs touch logs/error.log
次に実行をして見ましょう。
cd objs sudo ./nginx -c conf/nginx.conf
これで起動したはずです。
次はアクセスしたいですよね。アクセスを行うことを確認して見ましょう。今回はquicheのexampleを利用してアクセスします。
cd ../quiche cargo build --examples target/debug/examples/http3-client https://127.0.0.1:4443/index.html --no-verify |head -n3
結果としてはhtmlファイルを置いていないので以下のような感じでコネクションが解決してることがわかります!
<html> <head><title>403 Forbidden</title></head> <body>
確かにパケットが飛んできてそうですね〜!
まとめ
結構簡単にHTTP/3を体験できることがわかりました。自分の開発用に知ってると嬉しいかなと思って書いて見ました。 もし興味がある人は Chrome Canary
(開発バージョンのchrome)を利用して --enable-quic --quic-version=h3-23
を渡して起動するとHTTP/3が動いたりします!よければ遊んでみてください。
追記
yukiさんにコメントをいただいて、どうやらchromeの最新では--enable-quic --quic-version=h3-24
になったそうです。訂正させていただきます🙇♂️
最新版ですと、h3-23ではなくh3-24が必要ですー 「The latest Chrome Canary supports h3-24 instead of h3-23」 https://groups.google.com/a/chromium.org/forum/#!topic/proto-quic/trZsbXM_2CM