70d7c1a22c
* Add signal to the im test group * fix(ipconfig_test.go): disable when running in CI Reference issue: https://github.com/ooni/probe/issues/1418 * fix(geolocate): remove unused variable Came across this while looking into this issue with the CI that is now failing. Guess fixing it here comes across as leaving the camp slightly less in a bad shape than how I found it. Co-authored-by: Simone Basso <bassosimone@gmail.com>
120 lines
2.6 KiB
Go
120 lines
2.6 KiB
Go
package geolocate
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math/rand"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/engine/internal/multierror"
|
|
"github.com/ooni/probe-cli/v3/internal/engine/netx"
|
|
)
|
|
|
|
var (
|
|
// ErrAllIPLookuppersFailed indicates that we failed with looking
|
|
// up the probe IP for with all the lookuppers that we tried.
|
|
ErrAllIPLookuppersFailed = errors.New("all IP lookuppers failed")
|
|
|
|
// ErrInvalidIPAddress indicates that the code returned to us a
|
|
// string that actually isn't a valid IP address.
|
|
ErrInvalidIPAddress = errors.New("lookupper did not return a valid IP")
|
|
)
|
|
|
|
type lookupFunc func(
|
|
ctx context.Context, client *http.Client,
|
|
logger Logger, userAgent string,
|
|
) (string, error)
|
|
|
|
type method struct {
|
|
name string
|
|
fn lookupFunc
|
|
}
|
|
|
|
var (
|
|
methods = []method{
|
|
{
|
|
name: "avast",
|
|
fn: avastIPLookup,
|
|
},
|
|
{
|
|
name: "ipconfig",
|
|
fn: ipConfigIPLookup,
|
|
},
|
|
{
|
|
name: "ipinfo",
|
|
fn: ipInfoIPLookup,
|
|
},
|
|
{
|
|
name: "stun_ekiga",
|
|
fn: stunEkigaIPLookup,
|
|
},
|
|
{
|
|
name: "stun_google",
|
|
fn: stunGoogleIPLookup,
|
|
},
|
|
{
|
|
name: "ubuntu",
|
|
fn: ubuntuIPLookup,
|
|
},
|
|
}
|
|
)
|
|
|
|
type ipLookupClient struct {
|
|
// Resolver is the resolver to use for HTTP.
|
|
Resolver Resolver
|
|
|
|
// Logger is the logger to use
|
|
Logger Logger
|
|
|
|
// UserAgent is the user agent to use
|
|
UserAgent string
|
|
}
|
|
|
|
func makeSlice() []method {
|
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
ret := make([]method, len(methods))
|
|
perm := r.Perm(len(methods))
|
|
for idx, randIdx := range perm {
|
|
ret[idx] = methods[randIdx]
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (c ipLookupClient) doWithCustomFunc(
|
|
ctx context.Context, fn lookupFunc,
|
|
) (string, error) {
|
|
// Implementation note: we MUST use an HTTP client that we're
|
|
// sure IS NOT using any proxy. To this end, we construct a
|
|
// client ourself that we know is not proxied.
|
|
clnt := &http.Client{Transport: netx.NewHTTPTransport(netx.Config{
|
|
Logger: c.Logger,
|
|
FullResolver: c.Resolver,
|
|
})}
|
|
defer clnt.CloseIdleConnections()
|
|
ip, err := fn(ctx, clnt, c.Logger, c.UserAgent)
|
|
if err != nil {
|
|
return DefaultProbeIP, err
|
|
}
|
|
if net.ParseIP(ip) == nil {
|
|
return DefaultProbeIP, fmt.Errorf("%w: %s", ErrInvalidIPAddress, ip)
|
|
}
|
|
c.Logger.Debugf("iplookup: IP: %s", ip)
|
|
return ip, nil
|
|
}
|
|
|
|
func (c ipLookupClient) LookupProbeIP(ctx context.Context) (string, error) {
|
|
union := multierror.New(ErrAllIPLookuppersFailed)
|
|
for _, method := range makeSlice() {
|
|
c.Logger.Infof("iplookup: using %s", method.name)
|
|
ip, err := c.doWithCustomFunc(ctx, method.fn)
|
|
if err == nil {
|
|
return ip, nil
|
|
}
|
|
union.Add(err)
|
|
}
|
|
return DefaultProbeIP, union
|
|
}
|