"Call it TCP/2. One More Time."
ngtcp2 project is an effort to implement RFC9000 QUIC protocol.
Online documentation is available.
The following endpoints are available to try out ngtcp2 implementation:
https://nghttp2.org:4434 (requires address validation token)
https://nghttp2.org (powered by nghttpx)
This endpoints sends Alt-Svc header field to clients if it is accessed via HTTP/1.1 or HTTP/2 to tell them that HTTP/3 is available at UDP 443.
The libngtcp2 C library itself does not depend on any external libraries. The example client, and server are written in C++20, and should compile with the modern C++ compilers (e.g., clang >= 11.0, or gcc >= 11.0).
The following packages are required to configure the build system:
- pkg-config >= 0.20
- autoconf
- automake
- autotools-dev
- libtool
To build sources under the examples directory, libev and nghttp3 are required:
- libev
- nghttp3 for HTTP/3
To enable TLS Certificate Compression in bsslclient and bsslserver (BoringSSL (aws-lc) examples client and server), the following library is required:
- libbrotli-dev >= 1.0.9
ngtcp2 crypto helper library, and client and server under examples directory require at least one of the following TLS backends:
- quictls
- GnuTLS >= 3.7.5
- BoringSSL (commit a220a6024f66c123019b5c080f6bd8bcaf75448c); or aws-lc >= 1.19.0
- Picotls (commit e4f0a27ebd1c07ebed68674258da9556fb92b46b)
- wolfSSL >= 5.5.0
When build from git, run the following command to pull submodules:
$ git submodule update --init
$ git clone --depth 1 -b v5.7.0-stable https://github.com/wolfSSL/wolfssl
$ cd wolfssl
$ autoreconf -i
$ # For wolfSSL < v5.6.6, append --enable-quic.
$ ./configure --prefix=$PWD/build \
--enable-all --enable-aesni --enable-harden --enable-keylog-export \
--disable-ech
$ make -j$(nproc)
$ make install
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc) check
$ make install
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ # For Mac users who have installed libev with MacPorts, append
$ # LIBEV_CFLAGS="-I/opt/local/include" LIBEV_LIBS="-L/opt/local/lib -lev"
$ ./configure PKG_CONFIG_PATH=$PWD/../wolfssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig \
--with-wolfssl
$ make -j$(nproc) check
$ git clone https://boringssl.googlesource.com/boringssl
$ cd boringssl
$ git checkout a220a6024f66c123019b5c080f6bd8bcaf75448c
$ cmake -B build -DCMAKE_POSITION_INDEPENDENT_CODE=ON
$ make -j$(nproc) -C build
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc) check
$ make install
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ # For Mac users who have installed libev with MacPorts, append
$ # LIBEV_CFLAGS="-I/opt/local/include" LIBEV_LIBS="-L/opt/local/lib -lev"
$ ./configure PKG_CONFIG_PATH=$PWD/../nghttp3/build/lib/pkgconfig \
BORINGSSL_LIBS="-L$PWD/../boringssl/build/ssl -lssl -L$PWD/../boringssl/build/crypto -lcrypto" \
BORINGSSL_CFLAGS="-I$PWD/../boringssl/include" \
--with-boringssl
$ make -j$(nproc) check
$ git clone --depth 1 -b v1.29.0 https://github.com/aws/aws-lc
$ cd aws-lc
$ cmake -B build -DDISABLE_GO=ON
$ make -j$(nproc) -C build
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc) check
$ make install
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ # For Mac users who have installed libev with MacPorts, append
$ # LIBEV_CFLAGS="-I/opt/local/include" LIBEV_LIBS="-L/opt/local/lib -lev"
$ ./configure PKG_CONFIG_PATH=$PWD/../nghttp3/build/lib/pkgconfig \
BORINGSSL_CFLAGS="-I$PWD/../aws-lc/include" \
BORINGSSL_LIBS="-L$PWD/../aws-lc/build/ssl -lssl -L$PWD/../aws-lc/build/crypto -lcrypto" \
--with-boringssl
$ make -j$(nproc) check
$ git clone --depth 1 -b v3.9.2 https://github.com/libressl/portable.git libressl
$ cd libressl
$ ./autogen.sh
$ ./configure --prefix=$PWD/build
$ make -j$(nproc) install
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
$ make -j$(nproc) check
$ make install
$ cd ..
$ git clone --recursive https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ # For Mac users who have installed libev with MacPorts, append
$ # LIBEV_CFLAGS="-I/opt/homebrew/Cellar/libev/4.33/include" LIBEV_LIBS="-L/opt/homebrew/Cellar/libev/4.33/lib -lev"
$ ./configure PKG_CONFIG_PATH=$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../libressl/build/lib/pkgconfig
$ make -j$(nproc) check
After successful build, the client and server executable should be found under examples directory. They talk HTTP/3.
$ examples/wsslclient [OPTIONS] <HOST> <PORT> [<URI>...]
The notable options are:
-d
,--data=<PATH>
: Read data from <PATH> and send it to a peer.
$ examples/wsslserver [OPTIONS] <ADDR> <PORT> <PRIVATE_KEY_FILE> <CERTIFICATE_FILE>
The notable options are:
-V
,--validate-addr
: Enforce stateless address validation.
There are h09wsslclient and h09wsslserver which speak HTTP/0.9. They are written just for quic-interop-runner. They share the basic functionalities with HTTP/3 client and server but have less functions (e.g., h09wsslclient does not have a capability to send request body, and h09wsslserver does not understand numeric request path, like /1000).
In order to resume a session, a session ticket, and a transport parameters must be fetched from server. First, run examples/wsslclient with --session-file, and --tp-file options which specify a path to session ticket, and transport parameter files respectively to save them locally.
Once these files are available, run examples/wsslclient with the same arguments again. You will see that session is resumed in your log if resumption succeeds. Resuming session makes server's first Handshake packet pretty small because it does not send its certificates.
To send 0-RTT data, after making sure that resumption works, use -d option to specify a file which contains data to send.
QUIC server might send a token to client after connection has been established. Client can send this token in subsequent connection to the server. Server verifies the token and if it succeeds, the address validation completes and lifts some restrictions on server which might speed up transfer. In order to save and/or load a token, use --token-file option of examples/wsslclient. The given file is overwritten if it already exists when storing a token.
In order to make TLS stack integration less painful, we provide a crypto helper library which offers the basic crypto operations.
The header file exists under crypto/includes/ngtcp2 directory.
Each library file is built for a particular TLS backend. The available crypto helper libraries are:
- libngtcp2_crypto_quictls: Use quictls and libressl as TLS backend
- libngtcp2_crypto_gnutls: Use GnuTLS as TLS backend
- libngtcp2_crypto_boringssl: Use BoringSSL and aws-lc as TLS backend
- libngtcp2_crypto_picotls: Use Picotls as TLS backend
- libngtcp2_crypto_wolfssl: Use wolfSSL as TLS backend
Because BoringSSL and Picotls are an unversioned product, we only tested their particular revision. See Requirements section above.
We use Picotls with OpenSSL as crypto backend.
The examples directory contains client and server that are linked to those crypto helper libraries and TLS backends. They are only built if their corresponding crypto helper library is built:
- qtlsclient: quictls(libressl) client
- qtlsserver: quictls(libressl) server
- gtlsclient: GnuTLS client
- gtlsserver: GnuTLS server
- bsslclient: BoringSSL(aws-lc) client
- bsslserver: BoringSSL(aws-lc) server
- ptlsclient: Picotls client
- ptlsserver: Picotls server
- wsslclient: wolfSSL client
- wsslserver: wolfSSL server
The library implements the following QUIC protocol extensions:
- An Unreliable Datagram Extension to QUIC
- Greasing the QUIC Bit
- Compatible Version Negotiation for QUIC
- QUIC Version 2
Wireshark can be configured to analyze QUIC traffic using the following steps:
Set SSLKEYLOGFILE environment variable:
$ export SSLKEYLOGFILE=quic_keylog_file
Set the port that QUIC uses
Go to Preferences->Protocols->QUIC and set the port the program listens to. In the case of the example application this would be the port specified on the command line.
Set Pre-Master-Secret logfile
Go to Preferences->Protocols->TLS and set the Pre-Master-Secret log file to the same value that was specified for SSLKEYLOGFILE.
Choose the correct network interface for capturing
Make sure you choose the correct network interface for capturing. For example, if using localhost choose the loopback network interface on macos.
Create a filter
Create A filter for the udp.port and set the port to the port the application is listening to. For example:
udp.port == 7777
The MIT License
Copyright (c) 2016 ngtcp2 contributors