main: make --api option resolve hostnames via dns (#5249)
Resolves #5249. Calls multiaddr-dns, and picks the first result. Uses a fixed timeout of 10 seconds. Adds test cases for one, multiple, and no DNS results. License: MIT Signed-off-by: Raúl Kripalani <raul.kripalani@consensys.net>
Raúl Kripalani committed
Aug 11, 2018 at 23:26 UTC
0ddaf58336af04c9fe822262b2e2e000fecfd4ab
2 files changed
+94
-18
cmd/ipfs/dnsresolve_test.go
new
+72
@@ -0,0 +1,72 @@
1
+package main
2
+
3
+import (
4
+ "context"
5
+ "fmt"
6
+ "net"
7
+ "strings"
8
+ "testing"
9
+
10
+ ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
11
+ madns "gx/ipfs/QmfXU2MhWoegxHoeMd3A2ytL2P6CY4FfqGWc23LTNWBwZt/go-multiaddr-dns"
12
+)
13
+
14
+var (
15
+ ctx = context.Background()
16
+ testAddr, _ = ma.NewMultiaddr("/dns4/example.com/tcp/5001")
17
+)
18
+
19
+func makeResolver(n uint8) *madns.Resolver {
20
+ results := make([]net.IPAddr, n)
21
+ for i := uint8(0); i < n; i++ {
22
+ results[i] = net.IPAddr{IP: net.ParseIP(fmt.Sprintf("192.0.2.%d", i))}
23
+ }
24
+
25
+ backend := &madns.MockBackend{
26
+ IP: map[string][]net.IPAddr{
27
+ "example.com": results,
28
+ }}
29
+
30
+ return &madns.Resolver{
31
+ Backend: backend,
32
+ }
33
+}
34
+
35
+func TestApiEndpointResolveDNSOneResult(t *testing.T) {
36
+ dnsResolver = makeResolver(1)
37
+
38
+ addr, err := resolveAddr(ctx, testAddr)
39
+ if err != nil {
40
+ t.Error(err)
41
+ }
42
+
43
+ if ref, _ := ma.NewMultiaddr("/ip4/192.0.2.0/tcp/5001"); !addr.Equal(ref) {
44
+ t.Errorf("resolved address was different than expected")
45
+ }
46
+}
47
+
48
+func TestApiEndpointResolveDNSMultipleResults(t *testing.T) {
49
+ dnsResolver = makeResolver(4)
50
+
51
+ addr, err := resolveAddr(ctx, testAddr)
52
+ if err != nil {
53
+ t.Error(err)
54
+ }
55
+
56
+ if ref, _ := ma.NewMultiaddr("/ip4/192.0.2.0/tcp/5001"); !addr.Equal(ref) {
57
+ t.Errorf("resolved address was different than expected")
58
+ }
59
+}
60
+
61
+func TestApiEndpointResolveDNSNoResults(t *testing.T) {
62
+ dnsResolver = makeResolver(0)
63
+
64
+ addr, err := resolveAddr(ctx, testAddr)
65
+ if addr != nil || err == nil {
66
+ t.Error("expected test address not to resolve, and to throw an error")
67
+ }
68
+
69
+ if !strings.HasPrefix(err.Error(), "non-resolvable API endpoint") {
70
+ t.Errorf("expected error not thrown; actual: %v", err)
71
+ }
72
+}
cmd/ipfs/main.go
+22
-18
@@ -34,7 +34,7 @@ import (
34
osh "gx/ipfs/QmXuBJ7DR6k3rmUEKtvVMhwjmXDuJgXXPUt4LQXKBMsU93/go-os-helper"
35
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
36
loggables "gx/ipfs/QmZ4zF1mBrt8C2mSCM4ZYE4aAnv78f7GvrzufJC4G5tecK/go-libp2p-loggables"
37
- mdns "gx/ipfs/QmfXU2MhWoegxHoeMd3A2ytL2P6CY4FfqGWc23LTNWBwZt/go-multiaddr-dns"
37
+ madns "gx/ipfs/QmfXU2MhWoegxHoeMd3A2ytL2P6CY4FfqGWc23LTNWBwZt/go-multiaddr-dns"
38
)
39
40
// log is the command logger
@@ -42,6 +42,9 @@ var log = logging.Logger("cmd/ipfs")
42
43
var errRequestCanceled = errors.New("request canceled")
44
45
+// declared as a var for testing purposes
46
+var dnsResolver = madns.DefaultResolver
47
+
48
const (
49
EnvEnableProfiling = "IPFS_PROF"
50
cpuProfile = "ipfs.cpuprof"
@@ -445,30 +448,31 @@ func getApiClient(ctx context.Context, repoPath, apiAddrStr string) (http.Client
448
}
449
450
func apiClientForAddr(ctx context.Context, addr ma.Multiaddr) (http.Client, error) {
448
- addrs, err := mdns.Resolve(ctx, addr)
451
+ addr, err := resolveAddr(ctx, addr)
452
if err != nil {
453
return nil, err
454
}
455
453
- dialer := &manet.Dialer{}
454
- for _, addr := range addrs {
455
- ctx, cancelFunc := context.WithTimeout(ctx, 5*time.Second)
456
- defer cancelFunc()
456
+ _, host, err := manet.DialArgs(addr)
457
+ if err != nil {
458
+ return nil, err
459
+ }
460
458
- conn, err := dialer.DialContext(ctx, addr)
459
- if err != nil {
460
- log.Errorf("connection to %s failed, error: %s", addr, err)
461
- continue
462
- }
463
- conn.Close()
461
+ return http.NewClient(host, http.ClientWithAPIPrefix(corehttp.APIPath)), nil
462
+}
463
465
- _, host, err := manet.DialArgs(addr)
466
- if err != nil {
467
- continue
468
- }
464
+func resolveAddr(ctx context.Context, addr ma.Multiaddr) (ma.Multiaddr, error) {
465
+ ctx, cancelFunc := context.WithTimeout(ctx, 10*time.Second)
466
+ defer cancelFunc()
467
+
468
+ addrs, err := dnsResolver.Resolve(ctx, addr)
469
+ if err != nil {
470
+ return nil, err
471
+ }
472
470
- return http.NewClient(host, http.ClientWithAPIPrefix(corehttp.APIPath)), nil
473
+ if len(addrs) == 0 {
474
+ return nil, errors.New("non-resolvable API endpoint")
475
}
476
473
- return nil, errors.New("non-resolvable API endpoint")
477
+ return addrs[0], nil
478
}