refactor: spin geoipx off geolocate (#893)
A bunch of packages (including oohelperd) just need the ability to use MaxMind-like databases. They don't need the additional functionality implemented by the geolocate package. Such a package, in fact, is mostly (if not only) needed by the engine package. Therefore, move code to query MaxMind-like databases to a separate package, and avoid depending on geolocate in all the packages for which it's sufficient to use geoipx. Part of https://github.com/ooni/probe/issues/2240
This commit is contained in:
		
							parent
							
								
									1e7384d1cc
								
							
						
					
					
						commit
						110a11828b
					
				@ -11,7 +11,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/experiment/webconnectivity"
 | 
						"github.com/ooni/probe-cli/v3/internal/engine/experiment/webconnectivity"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
						"github.com/ooni/probe-cli/v3/internal/geoipx"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
						"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,7 +36,7 @@ func newIPInfo(creq *ctrlRequest, addrs []string) map[string]*webconnectivity.Co
 | 
				
			|||||||
		if netxlite.IsBogon(addr) { // note: we already excluded non-IP addrs above
 | 
							if netxlite.IsBogon(addr) { // note: we already excluded non-IP addrs above
 | 
				
			||||||
			flags |= webconnectivity.ControlIPInfoFlagIsBogon
 | 
								flags |= webconnectivity.ControlIPInfoFlagIsBogon
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		asn, _, _ := geolocate.LookupASN(addr) // AS0 on failure
 | 
							asn, _, _ := geoipx.LookupASN(addr) // AS0 on failure
 | 
				
			||||||
		ipinfo[addr] = &webconnectivity.ControlIPInfo{
 | 
							ipinfo[addr] = &webconnectivity.ControlIPInfo{
 | 
				
			||||||
			ASN:   int64(asn),
 | 
								ASN:   int64(asn),
 | 
				
			||||||
			Flags: flags,
 | 
								Flags: flags,
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,6 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/bytecounter"
 | 
						"github.com/ooni/probe-cli/v3/internal/bytecounter"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
					 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/probeservices"
 | 
						"github.com/ooni/probe-cli/v3/internal/engine/probeservices"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/version"
 | 
						"github.com/ooni/probe-cli/v3/internal/version"
 | 
				
			||||||
@ -199,7 +198,7 @@ func (e *experiment) newMeasurement(input string) *model.Measurement {
 | 
				
			|||||||
		Input:                     model.MeasurementTarget(input),
 | 
							Input:                     model.MeasurementTarget(input),
 | 
				
			||||||
		MeasurementStartTime:      utctimenow.Format(dateFormat),
 | 
							MeasurementStartTime:      utctimenow.Format(dateFormat),
 | 
				
			||||||
		MeasurementStartTimeSaved: utctimenow,
 | 
							MeasurementStartTimeSaved: utctimenow,
 | 
				
			||||||
		ProbeIP:                   geolocate.DefaultProbeIP,
 | 
							ProbeIP:                   model.DefaultProbeIP,
 | 
				
			||||||
		ProbeASN:                  e.session.ProbeASNString(),
 | 
							ProbeASN:                  e.session.ProbeASNString(),
 | 
				
			||||||
		ProbeCC:                   e.session.ProbeCC(),
 | 
							ProbeCC:                   e.session.ProbeCC(),
 | 
				
			||||||
		ProbeNetworkName:          e.session.ProbeNetworkName(),
 | 
							ProbeNetworkName:          e.session.ProbeNetworkName(),
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ package webconnectivity
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
						"github.com/ooni/probe-cli/v3/internal/geoipx"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/httpx"
 | 
						"github.com/ooni/probe-cli/v3/internal/httpx"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
						"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
				
			||||||
@ -122,9 +122,7 @@ func Control(
 | 
				
			|||||||
func (dns *ControlDNSResult) FillASNs(sess model.ExperimentSession) {
 | 
					func (dns *ControlDNSResult) FillASNs(sess model.ExperimentSession) {
 | 
				
			||||||
	dns.ASNs = []int64{}
 | 
						dns.ASNs = []int64{}
 | 
				
			||||||
	for _, ip := range dns.Addrs {
 | 
						for _, ip := range dns.Addrs {
 | 
				
			||||||
		// TODO(bassosimone): this would be more efficient if we'd open just
 | 
							asn, _, _ := geoipx.LookupASN(ip)
 | 
				
			||||||
		// once the database and then reuse it for every address.
 | 
					 | 
				
			||||||
		asn, _, _ := geolocate.LookupASN(ip)
 | 
					 | 
				
			||||||
		dns.ASNs = append(dns.ASNs, int64(asn))
 | 
							dns.ASNs = append(dns.ASNs, int64(asn))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@ func TestExperimentHonoursSharingDefaults(t *testing.T) {
 | 
				
			|||||||
		name:         "probeIP",
 | 
							name:         "probeIP",
 | 
				
			||||||
		locationInfo: &geolocate.Results{ProbeIP: "8.8.8.8"},
 | 
							locationInfo: &geolocate.Results{ProbeIP: "8.8.8.8"},
 | 
				
			||||||
		expect: func(m *model.Measurement) bool {
 | 
							expect: func(m *model.Measurement) bool {
 | 
				
			||||||
			return m.ProbeIP == geolocate.DefaultProbeIP
 | 
								return m.ProbeIP == model.DefaultProbeIP
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		name:         "probeASN",
 | 
							name:         "probeASN",
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ func cloudflareIPLookup(
 | 
				
			|||||||
		UserAgent:  model.HTTPHeaderUserAgent,
 | 
							UserAgent:  model.HTTPHeaderUserAgent,
 | 
				
			||||||
	}).WithBodyLogging().Build().FetchResource(ctx, "/cdn-cgi/trace")
 | 
						}).WithBodyLogging().Build().FetchResource(ctx, "/cdn-cgi/trace")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return DefaultProbeIP, err
 | 
							return model.DefaultProbeIP, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r := regexp.MustCompile("(?:ip)=(.*)")
 | 
						r := regexp.MustCompile("(?:ip)=(.*)")
 | 
				
			||||||
	ip := strings.Trim(string(r.Find(data)), "ip=")
 | 
						ip := strings.Trim(string(r.Find(data)), "ip=")
 | 
				
			||||||
 | 
				
			|||||||
@ -10,37 +10,6 @@ import (
 | 
				
			|||||||
	"github.com/ooni/probe-cli/v3/internal/version"
 | 
						"github.com/ooni/probe-cli/v3/internal/version"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					 | 
				
			||||||
	// DefaultProbeASN is the default probe ASN as a number.
 | 
					 | 
				
			||||||
	DefaultProbeASN uint = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultProbeCC is the default probe CC.
 | 
					 | 
				
			||||||
	DefaultProbeCC = "ZZ"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultProbeIP is the default probe IP.
 | 
					 | 
				
			||||||
	DefaultProbeIP = model.DefaultProbeIP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultProbeNetworkName is the default probe network name.
 | 
					 | 
				
			||||||
	DefaultProbeNetworkName = ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultResolverASN is the default resolver ASN.
 | 
					 | 
				
			||||||
	DefaultResolverASN uint = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultResolverIP is the default resolver IP.
 | 
					 | 
				
			||||||
	DefaultResolverIP = "127.0.0.2"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultResolverNetworkName is the default resolver network name.
 | 
					 | 
				
			||||||
	DefaultResolverNetworkName = ""
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
	// DefaultProbeASNString is the default probe ASN as a string.
 | 
					 | 
				
			||||||
	DefaultProbeASNString = fmt.Sprintf("AS%d", DefaultProbeASN)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// DefaultResolverASNString is the default resolver ASN as a string.
 | 
					 | 
				
			||||||
	DefaultResolverASNString = fmt.Sprintf("AS%d", DefaultResolverASN)
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Results contains geolocate results.
 | 
					// Results contains geolocate results.
 | 
				
			||||||
type Results struct {
 | 
					type Results struct {
 | 
				
			||||||
	// ASN is the autonomous system number.
 | 
						// ASN is the autonomous system number.
 | 
				
			||||||
@ -139,13 +108,13 @@ type Task struct {
 | 
				
			|||||||
func (op Task) Run(ctx context.Context) (*Results, error) {
 | 
					func (op Task) Run(ctx context.Context) (*Results, error) {
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	out := &Results{
 | 
						out := &Results{
 | 
				
			||||||
		ASN:                 DefaultProbeASN,
 | 
							ASN:                 model.DefaultProbeASN,
 | 
				
			||||||
		CountryCode:         DefaultProbeCC,
 | 
							CountryCode:         model.DefaultProbeCC,
 | 
				
			||||||
		NetworkName:         DefaultProbeNetworkName,
 | 
							NetworkName:         model.DefaultProbeNetworkName,
 | 
				
			||||||
		ProbeIP:             DefaultProbeIP,
 | 
							ProbeIP:             model.DefaultProbeIP,
 | 
				
			||||||
		ResolverASN:         DefaultResolverASN,
 | 
							ResolverASN:         model.DefaultResolverASN,
 | 
				
			||||||
		ResolverIP:          DefaultResolverIP,
 | 
							ResolverIP:          model.DefaultResolverIP,
 | 
				
			||||||
		ResolverNetworkName: DefaultResolverNetworkName,
 | 
							ResolverNetworkName: model.DefaultResolverNetworkName,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ip, err := op.probeIPLookupper.LookupProbeIP(ctx)
 | 
						ip, err := op.probeIPLookupper.LookupProbeIP(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,8 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type taskProbeIPLookupper struct {
 | 
					type taskProbeIPLookupper struct {
 | 
				
			||||||
@ -25,25 +27,25 @@ func TestLocationLookupCannotLookupProbeIP(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, expected) {
 | 
						if !errors.Is(err, expected) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ASN != DefaultProbeASN {
 | 
						if out.ASN != model.DefaultProbeASN {
 | 
				
			||||||
		t.Fatal("invalid ASN value")
 | 
							t.Fatal("invalid ASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.CountryCode != DefaultProbeCC {
 | 
						if out.CountryCode != model.DefaultProbeCC {
 | 
				
			||||||
		t.Fatal("invalid CountryCode value")
 | 
							t.Fatal("invalid CountryCode value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.NetworkName != DefaultProbeNetworkName {
 | 
						if out.NetworkName != model.DefaultProbeNetworkName {
 | 
				
			||||||
		t.Fatal("invalid NetworkName value")
 | 
							t.Fatal("invalid NetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ProbeIP != DefaultProbeIP {
 | 
						if out.ProbeIP != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatal("invalid ProbeIP value")
 | 
							t.Fatal("invalid ProbeIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverASN != DefaultResolverASN {
 | 
						if out.ResolverASN != model.DefaultResolverASN {
 | 
				
			||||||
		t.Fatal("invalid ResolverASN value")
 | 
							t.Fatal("invalid ResolverASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverIP != DefaultResolverIP {
 | 
						if out.ResolverIP != model.DefaultResolverIP {
 | 
				
			||||||
		t.Fatal("invalid ResolverIP value")
 | 
							t.Fatal("invalid ResolverIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverNetworkName != DefaultResolverNetworkName {
 | 
						if out.ResolverNetworkName != model.DefaultResolverNetworkName {
 | 
				
			||||||
		t.Fatal("invalid ResolverNetworkName value")
 | 
							t.Fatal("invalid ResolverNetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -69,25 +71,25 @@ func TestLocationLookupCannotLookupProbeASN(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, expected) {
 | 
						if !errors.Is(err, expected) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ASN != DefaultProbeASN {
 | 
						if out.ASN != model.DefaultProbeASN {
 | 
				
			||||||
		t.Fatal("invalid ASN value")
 | 
							t.Fatal("invalid ASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.CountryCode != DefaultProbeCC {
 | 
						if out.CountryCode != model.DefaultProbeCC {
 | 
				
			||||||
		t.Fatal("invalid CountryCode value")
 | 
							t.Fatal("invalid CountryCode value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.NetworkName != DefaultProbeNetworkName {
 | 
						if out.NetworkName != model.DefaultProbeNetworkName {
 | 
				
			||||||
		t.Fatal("invalid NetworkName value")
 | 
							t.Fatal("invalid NetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ProbeIP != "1.2.3.4" {
 | 
						if out.ProbeIP != "1.2.3.4" {
 | 
				
			||||||
		t.Fatal("invalid ProbeIP value")
 | 
							t.Fatal("invalid ProbeIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverASN != DefaultResolverASN {
 | 
						if out.ResolverASN != model.DefaultResolverASN {
 | 
				
			||||||
		t.Fatal("invalid ResolverASN value")
 | 
							t.Fatal("invalid ResolverASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverIP != DefaultResolverIP {
 | 
						if out.ResolverIP != model.DefaultResolverIP {
 | 
				
			||||||
		t.Fatal("invalid ResolverIP value")
 | 
							t.Fatal("invalid ResolverIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverNetworkName != DefaultResolverNetworkName {
 | 
						if out.ResolverNetworkName != model.DefaultResolverNetworkName {
 | 
				
			||||||
		t.Fatal("invalid ResolverNetworkName value")
 | 
							t.Fatal("invalid ResolverNetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -116,7 +118,7 @@ func TestLocationLookupCannotLookupProbeCC(t *testing.T) {
 | 
				
			|||||||
	if out.ASN != 1234 {
 | 
						if out.ASN != 1234 {
 | 
				
			||||||
		t.Fatal("invalid ASN value")
 | 
							t.Fatal("invalid ASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.CountryCode != DefaultProbeCC {
 | 
						if out.CountryCode != model.DefaultProbeCC {
 | 
				
			||||||
		t.Fatal("invalid CountryCode value")
 | 
							t.Fatal("invalid CountryCode value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.NetworkName != "1234.com" {
 | 
						if out.NetworkName != "1234.com" {
 | 
				
			||||||
@ -125,13 +127,13 @@ func TestLocationLookupCannotLookupProbeCC(t *testing.T) {
 | 
				
			|||||||
	if out.ProbeIP != "1.2.3.4" {
 | 
						if out.ProbeIP != "1.2.3.4" {
 | 
				
			||||||
		t.Fatal("invalid ProbeIP value")
 | 
							t.Fatal("invalid ProbeIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverASN != DefaultResolverASN {
 | 
						if out.ResolverASN != model.DefaultResolverASN {
 | 
				
			||||||
		t.Fatal("invalid ResolverASN value")
 | 
							t.Fatal("invalid ResolverASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverIP != DefaultResolverIP {
 | 
						if out.ResolverIP != model.DefaultResolverIP {
 | 
				
			||||||
		t.Fatal("invalid ResolverIP value")
 | 
							t.Fatal("invalid ResolverIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverNetworkName != DefaultResolverNetworkName {
 | 
						if out.ResolverNetworkName != model.DefaultResolverNetworkName {
 | 
				
			||||||
		t.Fatal("invalid ResolverNetworkName value")
 | 
							t.Fatal("invalid ResolverNetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -173,13 +175,13 @@ func TestLocationLookupCannotLookupResolverIP(t *testing.T) {
 | 
				
			|||||||
	if out.didResolverLookup != true {
 | 
						if out.didResolverLookup != true {
 | 
				
			||||||
		t.Fatal("invalid DidResolverLookup value")
 | 
							t.Fatal("invalid DidResolverLookup value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverASN != DefaultResolverASN {
 | 
						if out.ResolverASN != model.DefaultResolverASN {
 | 
				
			||||||
		t.Fatal("invalid ResolverASN value")
 | 
							t.Fatal("invalid ResolverASN value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverIP != DefaultResolverIP {
 | 
						if out.ResolverIP != model.DefaultResolverIP {
 | 
				
			||||||
		t.Fatal("invalid ResolverIP value")
 | 
							t.Fatal("invalid ResolverIP value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverNetworkName != DefaultResolverNetworkName {
 | 
						if out.ResolverNetworkName != model.DefaultResolverNetworkName {
 | 
				
			||||||
		t.Fatal("invalid ResolverNetworkName value")
 | 
							t.Fatal("invalid ResolverNetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -213,13 +215,13 @@ func TestLocationLookupCannotLookupResolverNetworkName(t *testing.T) {
 | 
				
			|||||||
	if out.didResolverLookup != true {
 | 
						if out.didResolverLookup != true {
 | 
				
			||||||
		t.Fatal("invalid DidResolverLookup value")
 | 
							t.Fatal("invalid DidResolverLookup value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverASN != DefaultResolverASN {
 | 
						if out.ResolverASN != model.DefaultResolverASN {
 | 
				
			||||||
		t.Fatalf("invalid ResolverASN value: %+v", out.ResolverASN)
 | 
							t.Fatalf("invalid ResolverASN value: %+v", out.ResolverASN)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverIP != "4.3.2.1" {
 | 
						if out.ResolverIP != "4.3.2.1" {
 | 
				
			||||||
		t.Fatalf("invalid ResolverIP value: %+v", out.ResolverIP)
 | 
							t.Fatalf("invalid ResolverIP value: %+v", out.ResolverIP)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if out.ResolverNetworkName != DefaultResolverNetworkName {
 | 
						if out.ResolverNetworkName != model.DefaultResolverNetworkName {
 | 
				
			||||||
		t.Fatal("invalid ResolverNetworkName value")
 | 
							t.Fatal("invalid ResolverNetworkName value")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -91,10 +91,10 @@ func (c ipLookupClient) doWithCustomFunc(
 | 
				
			|||||||
	defer clnt.CloseIdleConnections()
 | 
						defer clnt.CloseIdleConnections()
 | 
				
			||||||
	ip, err := fn(ctx, clnt, c.Logger, c.UserAgent)
 | 
						ip, err := fn(ctx, clnt, c.Logger, c.UserAgent)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return DefaultProbeIP, err
 | 
							return model.DefaultProbeIP, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if net.ParseIP(ip) == nil {
 | 
						if net.ParseIP(ip) == nil {
 | 
				
			||||||
		return DefaultProbeIP, fmt.Errorf("%w: %s", ErrInvalidIPAddress, ip)
 | 
							return model.DefaultProbeIP, fmt.Errorf("%w: %s", ErrInvalidIPAddress, ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	c.Logger.Debugf("iplookup: IP: %s", ip)
 | 
						c.Logger.Debugf("iplookup: IP: %s", ip)
 | 
				
			||||||
	return ip, nil
 | 
						return ip, nil
 | 
				
			||||||
@ -110,5 +110,5 @@ func (c ipLookupClient) LookupProbeIP(ctx context.Context) (string, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		union.Add(err)
 | 
							union.Add(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return DefaultProbeIP, union
 | 
						return model.DefaultProbeIP, union
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,7 @@ func TestIPLookupAllFailed(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, context.Canceled) {
 | 
						if !errors.Is(err, context.Canceled) {
 | 
				
			||||||
		t.Fatal("expected an error here")
 | 
							t.Fatal("expected an error here")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatal("expected the default IP here")
 | 
							t.Fatal("expected the default IP here")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -51,7 +51,7 @@ func TestIPLookupInvalidIP(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, ErrInvalidIPAddress) {
 | 
						if !errors.Is(err, ErrInvalidIPAddress) {
 | 
				
			||||||
		t.Fatal("expected an error here")
 | 
							t.Fatal("expected an error here")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatal("expected the default IP here")
 | 
							t.Fatal("expected the default IP here")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,54 +1,15 @@
 | 
				
			|||||||
package geolocate
 | 
					package geolocate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net"
 | 
						"github.com/ooni/probe-cli/v3/internal/geoipx"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/ooni/probe-assets/assets"
 | 
					 | 
				
			||||||
	"github.com/oschwald/geoip2-golang"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type mmdbLookupper struct{}
 | 
					type mmdbLookupper struct{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (mmdbLookupper) LookupASN(ip string) (asn uint, org string, err error) {
 | 
					func (mmdbLookupper) LookupASN(ip string) (uint, string, error) {
 | 
				
			||||||
	asn, org = DefaultProbeASN, DefaultProbeNetworkName
 | 
						return geoipx.LookupASN(ip)
 | 
				
			||||||
	db, err := geoip2.FromBytes(assets.ASNDatabaseData())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
	record, err := db.ASN(net.ParseIP(ip))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	asn = record.AutonomousSystemNumber
 | 
					 | 
				
			||||||
	if record.AutonomousSystemOrganization != "" {
 | 
					 | 
				
			||||||
		org = record.AutonomousSystemOrganization
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// LookupASN returns the ASN and the organization associated with the
 | 
					func (mmdbLookupper) LookupCC(ip string) (string, error) {
 | 
				
			||||||
// given IP address.
 | 
						return geoipx.LookupCC(ip)
 | 
				
			||||||
func LookupASN(ip string) (asn uint, org string, err error) {
 | 
					 | 
				
			||||||
	return (mmdbLookupper{}).LookupASN(ip)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (mmdbLookupper) LookupCC(ip string) (cc string, err error) {
 | 
					 | 
				
			||||||
	cc = DefaultProbeCC
 | 
					 | 
				
			||||||
	db, err := geoip2.FromBytes(assets.CountryDatabaseData())
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer db.Close()
 | 
					 | 
				
			||||||
	record, err := db.Country(net.ParseIP(ip))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// With MaxMind DB we used record.RegisteredCountry.IsoCode but that does
 | 
					 | 
				
			||||||
	// not seem to work with the db-ip.com database. The record is empty, at
 | 
					 | 
				
			||||||
	// least for my own IP address in Italy. --Simone (2020-02-25)
 | 
					 | 
				
			||||||
	if record.Country.IsoCode != "" {
 | 
					 | 
				
			||||||
		cc = record.Country.IsoCode
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,51 +0,0 @@
 | 
				
			|||||||
package geolocate
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import "testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ipAddr = "8.8.8.8"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLookupASN(t *testing.T) {
 | 
					 | 
				
			||||||
	asn, org, err := LookupASN(ipAddr)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if asn != 15169 {
 | 
					 | 
				
			||||||
		t.Fatal("unexpected ASN value", asn)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if org != "Google LLC" {
 | 
					 | 
				
			||||||
		t.Fatal("unexpected org value", org)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLookupASNInvalidIP(t *testing.T) {
 | 
					 | 
				
			||||||
	asn, org, err := LookupASN("xxx")
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatal("expected an error here")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if asn != DefaultProbeASN {
 | 
					 | 
				
			||||||
		t.Fatal("expected a zero ASN")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if org != DefaultProbeNetworkName {
 | 
					 | 
				
			||||||
		t.Fatal("expected an empty org")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLookupCC(t *testing.T) {
 | 
					 | 
				
			||||||
	cc, err := (mmdbLookupper{}).LookupCC(ipAddr)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		t.Fatal(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if cc != "US" {
 | 
					 | 
				
			||||||
		t.Fatal("invalid country code", cc)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestLookupCCInvalidIP(t *testing.T) {
 | 
					 | 
				
			||||||
	cc, err := (mmdbLookupper{}).LookupCC("xxx")
 | 
					 | 
				
			||||||
	if err == nil {
 | 
					 | 
				
			||||||
		t.Fatal("expected an error here")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if cc != DefaultProbeCC {
 | 
					 | 
				
			||||||
		t.Fatal("expected an empty cc")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -37,7 +37,7 @@ func stunIPLookup(ctx context.Context, config stunConfig) (string, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		clnt, err := dial("udp", config.Endpoint)
 | 
							clnt, err := dial("udp", config.Endpoint)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return DefaultProbeIP, err
 | 
								return model.DefaultProbeIP, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer clnt.Close()
 | 
							defer clnt.Close()
 | 
				
			||||||
		message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
 | 
							message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
 | 
				
			||||||
@ -55,20 +55,20 @@ func stunIPLookup(ctx context.Context, config stunConfig) (string, error) {
 | 
				
			|||||||
			ipch <- xorAddr.IP.String()
 | 
								ipch <- xorAddr.IP.String()
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return DefaultProbeIP, err
 | 
								return model.DefaultProbeIP, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case err := <-errch:
 | 
							case err := <-errch:
 | 
				
			||||||
			return DefaultProbeIP, err
 | 
								return model.DefaultProbeIP, err
 | 
				
			||||||
		case ip := <-ipch:
 | 
							case ip := <-ipch:
 | 
				
			||||||
			return ip, nil
 | 
								return ip, nil
 | 
				
			||||||
		case <-ctx.Done():
 | 
							case <-ctx.Done():
 | 
				
			||||||
			return DefaultProbeIP, ctx.Err()
 | 
								return model.DefaultProbeIP, ctx.Err()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		config.Logger.Debugf("STUNIPLookup: failure using %s: %+v", config.Endpoint, err)
 | 
							config.Logger.Debugf("STUNIPLookup: failure using %s: %+v", config.Endpoint, err)
 | 
				
			||||||
		return DefaultProbeIP, err
 | 
							return model.DefaultProbeIP, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ip, nil
 | 
						return ip, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ func TestSTUNIPLookupCanceledContext(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, context.Canceled) {
 | 
						if !errors.Is(err, context.Canceled) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatalf("not the IP address we expected: %+v", ip)
 | 
							t.Fatalf("not the IP address we expected: %+v", ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -41,7 +41,7 @@ func TestSTUNIPLookupDialFailure(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, expected) {
 | 
						if !errors.Is(err, expected) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatalf("not the IP address we expected: %+v", ip)
 | 
							t.Fatalf("not the IP address we expected: %+v", ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -79,7 +79,7 @@ func TestSTUNIPLookupStartReturnsError(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, expected) {
 | 
						if !errors.Is(err, expected) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatalf("not the IP address we expected: %+v", ip)
 | 
							t.Fatalf("not the IP address we expected: %+v", ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -99,7 +99,7 @@ func TestSTUNIPLookupStunEventContainsError(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, expected) {
 | 
						if !errors.Is(err, expected) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatalf("not the IP address we expected: %+v", ip)
 | 
							t.Fatalf("not the IP address we expected: %+v", ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -118,7 +118,7 @@ func TestSTUNIPLookupCannotDecodeMessage(t *testing.T) {
 | 
				
			|||||||
	if !errors.Is(err, stun.ErrAttributeNotFound) {
 | 
						if !errors.Is(err, stun.ErrAttributeNotFound) {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatalf("not the IP address we expected: %+v", ip)
 | 
							t.Fatalf("not the IP address we expected: %+v", ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,13 +27,13 @@ func ubuntuIPLookup(
 | 
				
			|||||||
		UserAgent:  userAgent,
 | 
							UserAgent:  userAgent,
 | 
				
			||||||
	}).WithBodyLogging().Build().FetchResource(ctx, "/lookup")
 | 
						}).WithBodyLogging().Build().FetchResource(ctx, "/lookup")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return DefaultProbeIP, err
 | 
							return model.DefaultProbeIP, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	logger.Debugf("ubuntu: body: %s", string(data))
 | 
						logger.Debugf("ubuntu: body: %s", string(data))
 | 
				
			||||||
	var v ubuntuResponse
 | 
						var v ubuntuResponse
 | 
				
			||||||
	err = xml.Unmarshal(data, &v)
 | 
						err = xml.Unmarshal(data, &v)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return DefaultProbeIP, err
 | 
							return model.DefaultProbeIP, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return v.IP, nil
 | 
						return v.IP, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ func TestUbuntuParseError(t *testing.T) {
 | 
				
			|||||||
	if err == nil || !strings.HasPrefix(err.Error(), "XML syntax error") {
 | 
						if err == nil || !strings.HasPrefix(err.Error(), "XML syntax error") {
 | 
				
			||||||
		t.Fatalf("not the error we expected: %+v", err)
 | 
							t.Fatalf("not the error we expected: %+v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ip != DefaultProbeIP {
 | 
						if ip != model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatalf("not the expected IP address: %s", ip)
 | 
							t.Fatalf("not the expected IP address: %s", ip)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -466,7 +466,7 @@ func (s *Session) ProbeASNString() string {
 | 
				
			|||||||
func (s *Session) ProbeASN() uint {
 | 
					func (s *Session) ProbeASN() uint {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	asn := geolocate.DefaultProbeASN
 | 
						asn := model.DefaultProbeASN
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		asn = s.location.ASN
 | 
							asn = s.location.ASN
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -477,7 +477,7 @@ func (s *Session) ProbeASN() uint {
 | 
				
			|||||||
func (s *Session) ProbeCC() string {
 | 
					func (s *Session) ProbeCC() string {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	cc := geolocate.DefaultProbeCC
 | 
						cc := model.DefaultProbeCC
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		cc = s.location.CountryCode
 | 
							cc = s.location.CountryCode
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -488,7 +488,7 @@ func (s *Session) ProbeCC() string {
 | 
				
			|||||||
func (s *Session) ProbeNetworkName() string {
 | 
					func (s *Session) ProbeNetworkName() string {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	nn := geolocate.DefaultProbeNetworkName
 | 
						nn := model.DefaultProbeNetworkName
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		nn = s.location.NetworkName
 | 
							nn = s.location.NetworkName
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -499,7 +499,7 @@ func (s *Session) ProbeNetworkName() string {
 | 
				
			|||||||
func (s *Session) ProbeIP() string {
 | 
					func (s *Session) ProbeIP() string {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	ip := geolocate.DefaultProbeIP
 | 
						ip := model.DefaultProbeIP
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		ip = s.location.ProbeIP
 | 
							ip = s.location.ProbeIP
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -520,7 +520,7 @@ func (s *Session) ResolverASNString() string {
 | 
				
			|||||||
func (s *Session) ResolverASN() uint {
 | 
					func (s *Session) ResolverASN() uint {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	asn := geolocate.DefaultResolverASN
 | 
						asn := model.DefaultResolverASN
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		asn = s.location.ResolverASN
 | 
							asn = s.location.ResolverASN
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -531,7 +531,7 @@ func (s *Session) ResolverASN() uint {
 | 
				
			|||||||
func (s *Session) ResolverIP() string {
 | 
					func (s *Session) ResolverIP() string {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	ip := geolocate.DefaultResolverIP
 | 
						ip := model.DefaultResolverIP
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		ip = s.location.ResolverIP
 | 
							ip = s.location.ResolverIP
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -542,7 +542,7 @@ func (s *Session) ResolverIP() string {
 | 
				
			|||||||
func (s *Session) ResolverNetworkName() string {
 | 
					func (s *Session) ResolverNetworkName() string {
 | 
				
			||||||
	defer s.mu.Unlock()
 | 
						defer s.mu.Unlock()
 | 
				
			||||||
	s.mu.Lock()
 | 
						s.mu.Lock()
 | 
				
			||||||
	nn := geolocate.DefaultResolverNetworkName
 | 
						nn := model.DefaultResolverNetworkName
 | 
				
			||||||
	if s.location != nil {
 | 
						if s.location != nil {
 | 
				
			||||||
		nn = s.location.ResolverNetworkName
 | 
							nn = s.location.ResolverNetworkName
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,6 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/apex/log"
 | 
						"github.com/apex/log"
 | 
				
			||||||
	"github.com/google/go-cmp/cmp"
 | 
						"github.com/google/go-cmp/cmp"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
					 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/probeservices"
 | 
						"github.com/ooni/probe-cli/v3/internal/engine/probeservices"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
						"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
				
			||||||
@ -276,31 +275,31 @@ func TestSessionLocationLookup(t *testing.T) {
 | 
				
			|||||||
	if err := sess.MaybeLookupLocation(); err != nil {
 | 
						if err := sess.MaybeLookupLocation(); err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ProbeASNString() == geolocate.DefaultProbeASNString {
 | 
						if sess.ProbeASNString() == model.DefaultProbeASNString {
 | 
				
			||||||
		t.Fatal("unexpected ProbeASNString")
 | 
							t.Fatal("unexpected ProbeASNString")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ProbeASN() == geolocate.DefaultProbeASN {
 | 
						if sess.ProbeASN() == model.DefaultProbeASN {
 | 
				
			||||||
		t.Fatal("unexpected ProbeASN")
 | 
							t.Fatal("unexpected ProbeASN")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ProbeCC() == geolocate.DefaultProbeCC {
 | 
						if sess.ProbeCC() == model.DefaultProbeCC {
 | 
				
			||||||
		t.Fatal("unexpected ProbeCC")
 | 
							t.Fatal("unexpected ProbeCC")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ProbeIP() == geolocate.DefaultProbeIP {
 | 
						if sess.ProbeIP() == model.DefaultProbeIP {
 | 
				
			||||||
		t.Fatal("unexpected ProbeIP")
 | 
							t.Fatal("unexpected ProbeIP")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ProbeNetworkName() == geolocate.DefaultProbeNetworkName {
 | 
						if sess.ProbeNetworkName() == model.DefaultProbeNetworkName {
 | 
				
			||||||
		t.Fatal("unexpected ProbeNetworkName")
 | 
							t.Fatal("unexpected ProbeNetworkName")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ResolverASN() == geolocate.DefaultResolverASN {
 | 
						if sess.ResolverASN() == model.DefaultResolverASN {
 | 
				
			||||||
		t.Fatal("unexpected ResolverASN")
 | 
							t.Fatal("unexpected ResolverASN")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ResolverASNString() == geolocate.DefaultResolverASNString {
 | 
						if sess.ResolverASNString() == model.DefaultResolverASNString {
 | 
				
			||||||
		t.Fatal("unexpected ResolverASNString")
 | 
							t.Fatal("unexpected ResolverASNString")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ResolverIP() == geolocate.DefaultResolverIP {
 | 
						if sess.ResolverIP() == model.DefaultResolverIP {
 | 
				
			||||||
		t.Fatal("unexpected ResolverIP")
 | 
							t.Fatal("unexpected ResolverIP")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if sess.ResolverNetworkName() == geolocate.DefaultResolverNetworkName {
 | 
						if sess.ResolverNetworkName() == model.DefaultResolverNetworkName {
 | 
				
			||||||
		t.Fatal("unexpected ResolverNetworkName")
 | 
							t.Fatal("unexpected ResolverNetworkName")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ import (
 | 
				
			|||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
						"github.com/ooni/probe-cli/v3/internal/geoipx"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
						"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -289,11 +289,11 @@ func (tk *TestKeys) analysisDNSDiffASN(probeAddrs, thAddrs []string) (asns []uin
 | 
				
			|||||||
	)
 | 
						)
 | 
				
			||||||
	mapping := make(map[uint]int)
 | 
						mapping := make(map[uint]int)
 | 
				
			||||||
	for _, addr := range probeAddrs {
 | 
						for _, addr := range probeAddrs {
 | 
				
			||||||
		asn, _, _ := geolocate.LookupASN(addr)
 | 
							asn, _, _ := geoipx.LookupASN(addr)
 | 
				
			||||||
		mapping[asn] |= inProbe // including the zero ASN that means unknown
 | 
							mapping[asn] |= inProbe // including the zero ASN that means unknown
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, addr := range thAddrs {
 | 
						for _, addr := range thAddrs {
 | 
				
			||||||
		asn, _, _ := geolocate.LookupASN(addr)
 | 
							asn, _, _ := geoipx.LookupASN(addr)
 | 
				
			||||||
		mapping[asn] |= inTH // including the zero ASN that means unknown
 | 
							mapping[asn] |= inTH // including the zero ASN that means unknown
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for asn, where := range mapping {
 | 
						for asn, where := range mapping {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										50
									
								
								internal/geoipx/geoipx.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								internal/geoipx/geoipx.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					// Package geoipx contains code to use the embedded MaxMind-like databases.
 | 
				
			||||||
 | 
					package geoipx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ooni/probe-assets/assets"
 | 
				
			||||||
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
 | 
						"github.com/ooni/probe-cli/v3/internal/runtimex"
 | 
				
			||||||
 | 
						"github.com/oschwald/geoip2-golang"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO(bassosimone): this would be more efficient if we'd open just
 | 
				
			||||||
 | 
					// once the database and then reuse it for every address.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LookupASN maps [ip] to an AS number and an AS organization name.
 | 
				
			||||||
 | 
					func LookupASN(ip string) (asn uint, org string, err error) {
 | 
				
			||||||
 | 
						asn, org = model.DefaultProbeASN, model.DefaultProbeNetworkName
 | 
				
			||||||
 | 
						db, err := geoip2.FromBytes(assets.ASNDatabaseData())
 | 
				
			||||||
 | 
						runtimex.PanicOnError(err, "cannot load embedded geoip2 ASN database")
 | 
				
			||||||
 | 
						defer db.Close()
 | 
				
			||||||
 | 
						record, err := db.ASN(net.ParseIP(ip))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						asn = record.AutonomousSystemNumber
 | 
				
			||||||
 | 
						if record.AutonomousSystemOrganization != "" {
 | 
				
			||||||
 | 
							org = record.AutonomousSystemOrganization
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LookupCC maps [ip] to a country code.
 | 
				
			||||||
 | 
					func LookupCC(ip string) (cc string, err error) {
 | 
				
			||||||
 | 
						cc = model.DefaultProbeCC
 | 
				
			||||||
 | 
						db, err := geoip2.FromBytes(assets.CountryDatabaseData())
 | 
				
			||||||
 | 
						runtimex.PanicOnError(err, "cannot load embedded geoip2 country database")
 | 
				
			||||||
 | 
						defer db.Close()
 | 
				
			||||||
 | 
						record, err := db.Country(net.ParseIP(ip))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// With MaxMind DB we used record.RegisteredCountry.IsoCode but that does
 | 
				
			||||||
 | 
						// not seem to work with the db-ip.com database. The record is empty, at
 | 
				
			||||||
 | 
						// least for my own IP address in Italy. --Simone (2020-02-25)
 | 
				
			||||||
 | 
						if record.Country.IsoCode != "" {
 | 
				
			||||||
 | 
							cc = record.Country.IsoCode
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										59
									
								
								internal/geoipx/geoipx_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								internal/geoipx/geoipx_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					package geoipx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ipAddr = "8.8.8.8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLookupASN(t *testing.T) {
 | 
				
			||||||
 | 
						t.Run("with valid IP address", func(t *testing.T) {
 | 
				
			||||||
 | 
							asn, org, err := LookupASN(ipAddr)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if asn != 15169 {
 | 
				
			||||||
 | 
								t.Fatal("unexpected ASN value", asn)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if org != "Google LLC" {
 | 
				
			||||||
 | 
								t.Fatal("unexpected org value", org)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Run("with invalid IP address", func(t *testing.T) {
 | 
				
			||||||
 | 
							asn, org, err := LookupASN("xxx")
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								t.Fatal("expected an error here")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if asn != model.DefaultProbeASN {
 | 
				
			||||||
 | 
								t.Fatal("expected a zero ASN")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if org != model.DefaultProbeNetworkName {
 | 
				
			||||||
 | 
								t.Fatal("expected an empty org")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestLookupCC(t *testing.T) {
 | 
				
			||||||
 | 
						t.Run("with valid IP address", func(t *testing.T) {
 | 
				
			||||||
 | 
							cc, err := LookupCC(ipAddr)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if cc != "US" {
 | 
				
			||||||
 | 
								t.Fatal("invalid country code", cc)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Run("with invalid IP address", func(t *testing.T) {
 | 
				
			||||||
 | 
							cc, err := LookupCC("xxx")
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								t.Fatal("expected an error here")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if cc != model.DefaultProbeCC {
 | 
				
			||||||
 | 
								t.Fatal("expected an empty cc")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -12,7 +12,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/miekg/dns"
 | 
						"github.com/miekg/dns"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
						"github.com/ooni/probe-cli/v3/internal/geoipx"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
						"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/tracex"
 | 
						"github.com/ooni/probe-cli/v3/internal/tracex"
 | 
				
			||||||
@ -163,7 +163,7 @@ func newArchivalDNSAnswers(addrs []string, resp model.DNSResponse) (out []model.
 | 
				
			|||||||
			log.Printf("BUG: NewArchivalDNSLookupResult: invalid IP address: %s", addr)
 | 
								log.Printf("BUG: NewArchivalDNSLookupResult: invalid IP address: %s", addr)
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		asn, org, _ := geolocate.LookupASN(addr)
 | 
							asn, org, _ := geoipx.LookupASN(addr)
 | 
				
			||||||
		switch ipv6 {
 | 
							switch ipv6 {
 | 
				
			||||||
		case false:
 | 
							case false:
 | 
				
			||||||
			out = append(out, model.ArchivalDNSAnswer{
 | 
								out = append(out, model.ArchivalDNSAnswer{
 | 
				
			||||||
 | 
				
			|||||||
@ -1,20 +1,47 @@
 | 
				
			|||||||
package model
 | 
					package model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"bytes"
 | 
					 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"errors"
 | 
					 | 
				
			||||||
	"net"
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// Definition of the result of a network measurement.
 | 
					// Definition of the result of a network measurement.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 | 
						// DefaultProbeASN is the default probe ASN as a number.
 | 
				
			||||||
 | 
						DefaultProbeASN uint = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DefaultProbeCC is the default probe CC.
 | 
				
			||||||
 | 
						DefaultProbeCC = "ZZ"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DefaultProbeIP is the default probe IP.
 | 
						// DefaultProbeIP is the default probe IP.
 | 
				
			||||||
	DefaultProbeIP = "127.0.0.1"
 | 
						DefaultProbeIP = "127.0.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DefaultProbeNetworkName is the default probe network name.
 | 
				
			||||||
 | 
						DefaultProbeNetworkName = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DefaultResolverASN is the default resolver ASN.
 | 
				
			||||||
 | 
						DefaultResolverASN uint = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DefaultResolverIP is the default resolver IP.
 | 
				
			||||||
 | 
						DefaultResolverIP = "127.0.0.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DefaultResolverNetworkName is the default resolver network name.
 | 
				
			||||||
 | 
						DefaultResolverNetworkName = ""
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						// DefaultProbeASNString is the default probe ASN as a string.
 | 
				
			||||||
 | 
						DefaultProbeASNString = fmt.Sprintf("AS%d", DefaultProbeASN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// DefaultResolverASNString is the default resolver ASN as a string.
 | 
				
			||||||
 | 
						DefaultResolverASNString = fmt.Sprintf("AS%d", DefaultResolverASN)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MeasurementTarget is the target of a OONI measurement.
 | 
					// MeasurementTarget is the target of a OONI measurement.
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
 | 
						"github.com/ooni/probe-cli/v3/internal/geoipx"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/model"
 | 
				
			||||||
	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
						"github.com/ooni/probe-cli/v3/internal/netxlite"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@ -201,7 +201,7 @@ func (qtype dnsQueryType) makeAnswerEntry(addr string) DNSAnswerEntry {
 | 
				
			|||||||
	answer := DNSAnswerEntry{AnswerType: string(qtype)}
 | 
						answer := DNSAnswerEntry{AnswerType: string(qtype)}
 | 
				
			||||||
	// Figuring out the ASN and the org here is not just a service to whoever
 | 
						// Figuring out the ASN and the org here is not just a service to whoever
 | 
				
			||||||
	// is reading a JSON: Web Connectivity also depends on it!
 | 
						// is reading a JSON: Web Connectivity also depends on it!
 | 
				
			||||||
	asn, org, _ := geolocate.LookupASN(addr)
 | 
						asn, org, _ := geoipx.LookupASN(addr)
 | 
				
			||||||
	answer.ASN = int64(asn)
 | 
						answer.ASN = int64(asn)
 | 
				
			||||||
	answer.ASOrgName = org
 | 
						answer.ASOrgName = org
 | 
				
			||||||
	switch qtype {
 | 
						switch qtype {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user