/
factory.go
99 lines (93 loc) · 3.07 KB
/
factory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package engineresolver
import (
"errors"
"net/url"
"github.com/ooni/probe-engine/pkg/bytecounter"
"github.com/ooni/probe-engine/pkg/model"
"github.com/ooni/probe-engine/pkg/netxlite"
"github.com/ooni/probe-engine/pkg/runtimex"
)
// errCannotUseHTTP3WithAProxyURL means we cannot construct a new
// child resolver using HTTP/3 with a proxy URL.
var errCannotUseHTTP3WithAProxyURL = errors.New("cannot use HTTP/3 with a proxy URL")
// errUnsupportedResolverScheme means we don't support the
// given resolver scheme. We only support https, http and system.
var errUnsupportedResolverScheme = errors.New("unsupported resolver scheme")
// newChildResolver constructs a new child resolver.
//
// Arguments:
//
// - logger is the MANDATORY logger;
//
// - URL is the MANDATORY URL to use (a DoH URL or system:///);
//
// - http3Enabled indicates whether to use HTTP/3;
//
// - counter is the OPTIONAL byte counter;
//
// - proxyURL is the OPTIONAL proxy URL.
//
// Using a proxy URL is incompatible with using HTTP/3 and this
// factory will return an error if that happens.
//
// This function returns a model.Resolver or an error.
func newChildResolver(
logger model.Logger,
URL string,
http3Enabled bool,
counter *bytecounter.Counter,
proxyURL *url.URL,
) (model.Resolver, error) {
runtimex.Assert(logger != nil, "passed a nil model.Logger")
runtimex.Assert(URL != "", "passed an empty URL")
if http3Enabled && proxyURL != nil {
return nil, errCannotUseHTTP3WithAProxyURL
}
parsed, err := url.Parse(URL)
if err != nil {
return nil, err
}
var reso model.Resolver
switch parsed.Scheme {
case "http", "https": // http is here for testing
reso = newChildResolverHTTPS(logger, URL, http3Enabled, counter, proxyURL)
case "system":
reso = bytecounter.MaybeWrapSystemResolver(
netxlite.NewStdlibResolver(logger),
counter, // handles correctly the case where counter is nil
)
default:
return nil, errUnsupportedResolverScheme
}
reso = netxlite.MaybeWrapWithBogonResolver(true, reso)
return reso, nil
}
// newChildResolverHTTPS is like newChildResolver but assumes that
// we already know that the URL scheme is http or https.
func newChildResolverHTTPS(
logger model.Logger,
URL string,
http3Enabled bool,
counter *bytecounter.Counter,
proxyURL *url.URL,
) model.Resolver {
var txp model.HTTPTransport
switch http3Enabled {
case false:
dialer := netxlite.NewDialerWithStdlibResolver(logger)
thx := netxlite.NewTLSHandshakerStdlib(logger)
tlsDialer := netxlite.NewTLSDialer(dialer, thx)
txp = netxlite.NewHTTPTransportWithOptions(
logger, dialer, tlsDialer,
netxlite.HTTPTransportOptionDisableCompression(false), // defaults to true but compression is fine here
netxlite.HTTPTransportOptionProxyURL(proxyURL), // nil here disables using the proxy
)
case true:
txp = netxlite.NewHTTP3TransportStdlib(logger)
}
txp = bytecounter.MaybeWrapHTTPTransport(txp, counter)
dnstxp := netxlite.NewDNSOverHTTPSTransportWithHTTPTransport(txp, URL)
underlying := netxlite.NewUnwrappedParallelResolver(dnstxp)
wrapped := netxlite.WrapResolver(logger, underlying)
return wrapped
}