お腹.ヘッタ。

関数型とかセキュリティとか勉強したい。進捗つらぽよ

Quicheをnginxで利用するためにmac向けにbuildして見た

adventar.org

これはSecHack365 修了生 Advent Calendar 2019の24日目記事です。

これは何

なんで俺はクリスマスイブにこんなこと書いてるんだろうか CloudflareのHTTP/3ライブラリ QuicheはRustで書かれているツールです。

github.com

この前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>

確かにパケットが飛んできてそうですね〜!

f:id:taketarou2:20191224135600p:plain
dump

まとめ

結構簡単にHTTP/3を体験できることがわかりました。自分の開発用に知ってると嬉しいかなと思って書いて見ました。 もし興味がある人は Chrome Canary

www.google.com

(開発バージョンの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