netxlite: call getaddrinfo and handle platform-specific oddities (#764)

This commit changes our system resolver to call getaddrinfo directly when CGO is enabled. This change allows us to:

1. obtain the CNAME easily

2. obtain the real getaddrinfo retval

3. handle platform specific oddities such as `EAI_NODATA`
returned on Android devices

See https://github.com/ooni/probe/issues/2029 and https://github.com/ooni/probe/issues/2029#issuecomment-1140258729 in particular.

See https://github.com/ooni/probe/issues/2033 for documentation regarding the desire to see `getaddrinfo`'s retval.

See https://github.com/ooni/probe/issues/2118 for possible follow-up changes.
This commit is contained in:
Simone Basso
2022-05-28 15:10:30 +02:00
committed by GitHub
parent 62bd62ece1
commit cf6dbe48e0
36 changed files with 1259 additions and 59 deletions
@@ -68,7 +68,7 @@ func (tk *TestKeys) classify() string {
return classAnomalyTestHelperUnreachable
case netxlite.FailureConnectionReset:
return classInterferenceReset
case netxlite.FailureDNSNXDOMAINError:
case netxlite.FailureDNSNXDOMAINError, netxlite.FailureAndroidDNSCacheNoData:
return classAnomalyTestHelperUnreachable
case netxlite.FailureEOFError:
return classInterferenceClosed
@@ -12,11 +12,6 @@ import (
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
const (
softwareName = "ooniprobe-example"
softwareVersion = "0.0.1"
)
func TestTestKeysClassify(t *testing.T) {
asStringPtr := func(s string) *string {
return &s
@@ -41,6 +36,13 @@ func TestTestKeysClassify(t *testing.T) {
t.Fatal("unexpected result")
}
})
t.Run("with tk.Target.Failure == android_dns_cache_no_data", func(t *testing.T) {
tk := new(TestKeys)
tk.Target.Failure = asStringPtr(netxlite.FailureAndroidDNSCacheNoData)
if tk.classify() != classAnomalyTestHelperUnreachable {
t.Fatal("unexpected result")
}
})
t.Run("with tk.Target.Failure == connection_reset", func(t *testing.T) {
tk := new(TestKeys)
tk.Target.Failure = asStringPtr(netxlite.FailureConnectionReset)
@@ -44,7 +44,13 @@ func DNSAnalysis(URL *url.URL, measurement DNSLookupResult,
switch *control.DNS.Failure {
case DNSNameError: // the control returns this on NXDOMAIN error
switch *measurement.Failure {
case netxlite.FailureDNSNXDOMAINError:
// When the Android getaddrinfo cache says "no data" (meaning basically
// "I don't know, mate") _and_ the test helper says NXDOMAIN, we can
// be ~confident that there's also NXDOMAIN on the Android side.
//
// See also https://github.com/ooni/probe/issues/2029.
case netxlite.FailureDNSNXDOMAINError,
netxlite.FailureAndroidDNSCacheNoData:
out.DNSConsistency = &DNSConsistent
}
}
@@ -14,6 +14,7 @@ func TestDNSAnalysis(t *testing.T) {
measurementFailure := netxlite.FailureDNSNXDOMAINError
controlFailure := webconnectivity.DNSNameError
eofFailure := io.EOF.Error()
androidEaiNoData := netxlite.FailureAndroidDNSCacheNoData
type args struct {
URL *url.URL
measurement webconnectivity.DNSLookupResult
@@ -57,7 +58,7 @@ func TestDNSAnalysis(t *testing.T) {
DNSConsistency: &webconnectivity.DNSInconsistent,
},
}, {
name: "when the failures are compatible",
name: "when the failures are compatible (NXDOMAIN case)",
args: args{
URL: &url.URL{
Host: "www.kerneltrap.org",
@@ -74,6 +75,24 @@ func TestDNSAnalysis(t *testing.T) {
wantOut: webconnectivity.DNSAnalysisResult{
DNSConsistency: &webconnectivity.DNSConsistent,
},
}, {
name: "when the failures are compatible (Android EAI_NODATA case)",
args: args{
URL: &url.URL{
Host: "www.kerneltrap.org",
},
measurement: webconnectivity.DNSLookupResult{
Failure: &androidEaiNoData,
},
control: webconnectivity.ControlResponse{
DNS: webconnectivity.ControlDNSResult{
Failure: &controlFailure,
},
},
},
wantOut: webconnectivity.DNSAnalysisResult{
DNSConsistency: &webconnectivity.DNSConsistent,
},
}, {
name: "when the ASNs are equal",
args: args{
@@ -125,9 +125,14 @@ func Summarize(tk *TestKeys) (out Summary) {
return
}
// If DNS failed with NXDOMAIN and the control DNS is consistent, then it
// means this website does not exist anymore.
// means this website does not exist anymore. We need to include the weird
// cache failure on Android into this analysis because that failure means
// NXDOMAIN (well, most likely) if the TH reported NXDOMAIN.
//
// See https://github.com/ooni/probe/issues/2029 for the Android issue.
if tk.DNSExperimentFailure != nil &&
*tk.DNSExperimentFailure == netxlite.FailureDNSNXDOMAINError &&
(*tk.DNSExperimentFailure == netxlite.FailureDNSNXDOMAINError ||
*tk.DNSExperimentFailure == netxlite.FailureAndroidDNSCacheNoData) &&
tk.DNSConsistency != nil && *tk.DNSConsistency == DNSConsistent {
// TODO(bassosimone): MK flags this as accessible. This result is debatable. We
// are doing what MK does. But we most likely want to make it better later.
@@ -26,6 +26,7 @@ func TestSummarize(t *testing.T) {
probeSSLInvalidHost = netxlite.FailureSSLInvalidHostname
probeSSLInvalidCert = netxlite.FailureSSLInvalidCertificate
probeSSLUnknownAuth = netxlite.FailureSSLUnknownAuthority
probeAndroidEaiNoData = netxlite.FailureAndroidDNSCacheNoData
tcpIP = "tcp_ip"
trueValue = true
)
@@ -68,7 +69,7 @@ func TestSummarize(t *testing.T) {
Status: webconnectivity.StatusAnomalyControlUnreachable,
},
}, {
name: "with non-existing website",
name: "with non-existing website (NXDOMAIN case)",
args: args{
tk: &webconnectivity.TestKeys{
DNSExperimentFailure: &probeNXDOMAIN,
@@ -84,6 +85,23 @@ func TestSummarize(t *testing.T) {
Status: webconnectivity.StatusSuccessNXDOMAIN |
webconnectivity.StatusExperimentDNS,
},
}, {
name: "with non-existing website (Android EAI_NODATA case)",
args: args{
tk: &webconnectivity.TestKeys{
DNSExperimentFailure: &probeAndroidEaiNoData,
DNSAnalysisResult: webconnectivity.DNSAnalysisResult{
DNSConsistency: &webconnectivity.DNSConsistent,
},
},
},
wantOut: webconnectivity.Summary{
BlockingReason: nil,
Blocking: false,
Accessible: &trueValue,
Status: webconnectivity.StatusSuccessNXDOMAIN |
webconnectivity.StatusExperimentDNS,
},
}, {
name: "with NXDOMAIN measured only by the probe",
args: args{