chapter04

command
v3.19.0-alpha.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2023 License: GPL-3.0 Imports: 9 Imported by: 0

README

Chapter I: Using QUIC

In this chapter we will write together a main.go file that uses netxlite to establish a new QUIC connection with an UDP endpoint.

Conceptually, this program is very similar to the ones presented in chapters 2 and 3, except that here we use QUIC.

(This file is auto-generated from the corresponding source file, so make sure you don't edit it manually.)

The main.go file

We define main.go file using package main.

The beginning of the program is equal to the previous chapters, so there is not much to say about it.

package main

import (
	"context"
	"crypto/tls"
	"errors"
	"flag"
	"os"
	"time"

	"github.com/apex/log"
	"github.com/ooni/probe-cli/v3/internal/netxlite"
	"github.com/quic-go/quic-go"
)

func main() {
	log.SetLevel(log.DebugLevel)
	address := flag.String("address", "8.8.4.4:443", "Remote endpoint address")
	sni := flag.String("sni", "dns.google", "SNI to use")
	timeout := flag.Duration("timeout", 60*time.Second, "Timeout")
	flag.Parse()
	ctx, cancel := context.WithTimeout(context.Background(), *timeout)
	defer cancel()

The main difference is that we set the ALPN correctly for QUIC/HTTP3 by using "h3" here.

	config := &tls.Config{
		ServerName: *sni,
		NextProtos: []string{"h3"},
		RootCAs:    nil,
	}

Also, where previously we called dialTLS now we call a function with a similar API called dialQUIC.

	qconn, state, err := dialQUIC(ctx, *address, config)

The rest of the main function is pretty much the same.

	if err != nil {
		fatal(err)
	}
	log.Infof("Connection type          : %T", qconn)
	log.Infof("Cipher suite       : %s", netxlite.TLSCipherSuiteString(state.CipherSuite))
	log.Infof("Negotiated protocol: %s", state.NegotiatedProtocol)
	log.Infof("TLS version        : %s", netxlite.TLSVersionString(state.Version))
	qconn.CloseWithError(0, "")
}

The dialQUIC function is new. We need to create a QUIC listener and, using it, a QUICDialer. These two steps are separated so higher level code can wrap the QUICDialer and collect stats on the returned connections. Also, as previously, this dialer is not attached to a resolver, so it will fail if provided a domain name. The rationale for doing that is similar to before: we are focusing on step-by-step measurements where each operation is performed independently. (That is, we assume that before the code written in this main we have already resolved the domain name of interest using a resolver, which we will investigate in the next two chapters.)

func dialQUIC(ctx context.Context, address string,
	config *tls.Config) (quic.EarlyConnection, tls.ConnectionState, error) {
	ql := netxlite.NewUDPListener()
	d := netxlite.NewQUICDialerWithoutResolver(ql, log.Log)
	qconn, err := d.DialContext(ctx, address, config, &quic.Config{})
	if err != nil {
		return nil, tls.ConnectionState{}, err
	}

The following line unwraps the connection state returned by QUIC code to be of the same type of the ConnectionState that we returned in the previous chapters.

	return qconn, qconn.ConnectionState().TLS, nil
}

The rest of the program is equal to the previous chapters.

func fatal(err error) {
	var ew *netxlite.ErrWrapper
	if !errors.As(err, &ew) {
		log.Fatal("cannot get ErrWrapper")
	}
	log.Warnf("error string    : %s", err.Error())
	log.Warnf("OONI failure    : %s", ew.Failure)
	log.Warnf("failed operation: %s", ew.Operation)
	log.Warnf("underlying error: %+v", ew.WrappedErr)
	os.Exit(1)
}

Running the code

Vanilla run

You can now run this code as follows:

go run -race ./internal/tutorial/netxlite/chapter04

You will see debug logs describing what is happening along with timing info.

QUIC handshake timeout
go run -race ./internal/tutorial/netxlite/chapter04 -address 8.8.4.4:1

should cause a QUIC timeout error. Try lowering the timout adding, e.g., the -timeout 5s flag to the command line.

SNI mismatch
go run -race ./internal/tutorial/netxlite/chapter04 -sni example.com

should give you a TLS error mentioning that the certificate is invalid.

Conclusions

We have seen how to use netxlite to establish a QUIC connection with a remote UDP endpoint speaking QUIC.

Documentation

Overview

-=-=- StartHere -=-=-

Chapter I: Using QUIC

In this chapter we will write together a `main.go` file that uses netxlite to establish a new QUIC connection with an UDP endpoint.

Conceptually, this program is very similar to the ones presented in chapters 2 and 3, except that here we use QUIC.

(This file is auto-generated from the corresponding source file, so make sure you don't edit it manually.)

## The main.go file

We define `main.go` file using `package main`.

The beginning of the program is equal to the previous chapters, so there is not much to say about it.

```Go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL