ooni-probe-cli/internal/tutorial/netxlite/chapter05
Simone Basso 9ef4d9df7d
doc: add tutorial on how to use netxlite (#519)
The main tutorial will be the one at https://github.com/ooni/probe-cli/pull/506, but
it's useful to also document the primitives used by measurex.

So, here's the companion tutorial, which explains how to use the
features in netxlite to perform measurements.

This work is part of https://github.com/ooni/ooni.org/issues/361.
2021-09-28 18:15:38 +02:00
..
main.go doc: add tutorial on how to use netxlite (#519) 2021-09-28 18:15:38 +02:00
README.md doc: add tutorial on how to use netxlite (#519) 2021-09-28 18:15:38 +02:00

Chapter I: Using the "system" DNS resolver

In this chapter we will write together a main.go file that uses the "system" DNS resolver to lookup domain names.

The "system" resolver is the one used by getaddrinfo on Unix.

(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.

package main

import (
	"context"
	"errors"
	"flag"
	"os"
	"time"

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

func main() {

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

	log.SetLevel(log.DebugLevel)
	hostname := flag.String("hostname", "dns.google", "Hostname to resolve")
	timeout := flag.Duration("timeout", 60*time.Second, "Timeout")
	flag.Parse()
	ctx, cancel := context.WithTimeout(context.Background(), *timeout)
	defer cancel()

We create a new resolver using the standard library to perform domain name resolutions. Unless you're cross compiling, this resolver will call the system resolver using a C API. On Unix the called C API is getaddrinfo.

The returned resolver implements an interface that is very close to the API of the net.Resolver struct.

	reso := netxlite.NewResolverStdlib(log.Log)

We call LookupHost to map the hostname to IP addrs. The returned value is either a list of addrs or an error.

	addrs, err := reso.LookupHost(ctx, *hostname)
	if err != nil {
		fatal(err)
	}
	log.Infof("resolver addrs: %+v", addrs)
}

This function is exactly like it was in 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/chapter05

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

NXDOMAIN error

go run -race ./internal/tutorial/netxlite/chapter05 -hostname antani.ooni.io

should cause a dns_nxdomain_error, because the domain does not exist.

Timeout

go run -race ./internal/tutorial/netxlite/chapter05 -timeout 10us

should cause a timeout error, because the timeout is ridicolously small.

Conclusions

We have seen how to use the "system" DNS resolver.