1package madns
2
3import (
4	"context"
5	"net"
6	"testing"
7
8	ma "github.com/multiformats/go-multiaddr"
9)
10
11var ip4a = net.IPAddr{IP: net.ParseIP("192.0.2.1")}
12var ip4b = net.IPAddr{IP: net.ParseIP("192.0.2.2")}
13var ip6a = net.IPAddr{IP: net.ParseIP("2001:db8::a3")}
14var ip6b = net.IPAddr{IP: net.ParseIP("2001:db8::a4")}
15
16var ip4ma = ma.StringCast("/ip4/" + ip4a.IP.String())
17var ip4mb = ma.StringCast("/ip4/" + ip4b.IP.String())
18var ip6ma = ma.StringCast("/ip6/" + ip6a.IP.String())
19var ip6mb = ma.StringCast("/ip6/" + ip6b.IP.String())
20
21var txtmc = ma.Join(ip4ma, ma.StringCast("/tcp/123/http"))
22var txtmd = ma.Join(ip4ma, ma.StringCast("/tcp/123"))
23var txtme = ma.Join(ip4ma, ma.StringCast("/tcp/789/http"))
24
25var txta = "dnsaddr=" + ip4ma.String()
26var txtb = "dnsaddr=" + ip6ma.String()
27var txtc = "dnsaddr=" + txtmc.String()
28var txtd = "dnsaddr=" + txtmd.String()
29var txte = "dnsaddr=" + txtme.String()
30
31func makeResolver() *Resolver {
32	mock := &MockBackend{
33		IP: map[string][]net.IPAddr{
34			"example.com": []net.IPAddr{ip4a, ip4b, ip6a, ip6b},
35		},
36		TXT: map[string][]string{
37			"_dnsaddr.example.com":  []string{txta, txtb},
38			"_dnsaddr.matching.com": []string{txtc, txtd, txte, "not a dnsaddr", "dnsaddr=/foobar"},
39		},
40	}
41	resolver := &Resolver{Backend: mock}
42	return resolver
43}
44
45func TestMatches(t *testing.T) {
46	if !Matches(ma.StringCast("/tcp/1234/dns6/example.com")) {
47		// Pretend this is a p2p-circuit address. Unfortunately, we'd
48		// need to depend on the circuit package to parse it.
49		t.Fatalf("expected match, didn't: /tcp/1234/dns6/example.com")
50	}
51	if !Matches(ma.StringCast("/dns/example.com")) {
52		t.Fatalf("expected match, didn't: /dns/example.com")
53	}
54	if !Matches(ma.StringCast("/dns4/example.com")) {
55		t.Fatalf("expected match, didn't: /dns4/example.com")
56	}
57	if !Matches(ma.StringCast("/dns6/example.com")) {
58		t.Fatalf("expected match, didn't: /dns6/example.com")
59	}
60	if !Matches(ma.StringCast("/dnsaddr/example.com")) {
61		t.Fatalf("expected match, didn't: /dnsaddr/example.com")
62	}
63	if Matches(ip4ma) {
64		t.Fatalf("expected no-match, but did: %s", ip4ma.String())
65	}
66}
67
68func TestSimpleIPResolve(t *testing.T) {
69	ctx := context.Background()
70	resolver := makeResolver()
71
72	addrs4, err := resolver.Resolve(ctx, ma.StringCast("/dns4/example.com"))
73	if err != nil {
74		t.Error(err)
75	}
76	if len(addrs4) != 2 || !addrs4[0].Equal(ip4ma) || addrs4[0].Equal(ip4mb) {
77		t.Fatalf("expected [%s %s], got %+v", ip4ma, ip4mb, addrs4)
78	}
79
80	addrs6, err := resolver.Resolve(ctx, ma.StringCast("/dns6/example.com"))
81	if err != nil {
82		t.Error(err)
83	}
84	if len(addrs6) != 2 || !addrs6[0].Equal(ip6ma) || addrs6[0].Equal(ip6mb) {
85		t.Fatalf("expected [%s %s], got %+v", ip6ma, ip6mb, addrs6)
86	}
87
88	addrs, err := resolver.Resolve(ctx, ma.StringCast("/dns/example.com"))
89	if err != nil {
90		t.Error(err)
91	}
92	for i, expected := range []ma.Multiaddr{ip4ma, ip4mb, ip6ma, ip6mb} {
93		if !expected.Equal(addrs[i]) {
94			t.Fatalf("%d: expected %s, got %s", i, expected, addrs[i])
95		}
96	}
97}
98
99func TestResolveMultiple(t *testing.T) {
100	ctx := context.Background()
101	resolver := makeResolver()
102
103	addrs, err := resolver.Resolve(ctx, ma.StringCast("/dns4/example.com/quic/dns6/example.com"))
104	if err != nil {
105		t.Error(err)
106	}
107	for i, x := range []ma.Multiaddr{ip4ma, ip4mb} {
108		for j, y := range []ma.Multiaddr{ip6ma, ip6mb} {
109			expected := ma.Join(x, ma.StringCast("/quic"), y)
110			actual := addrs[i*2+j]
111			if !expected.Equal(actual) {
112				t.Fatalf("expected %s, got %s", expected, actual)
113			}
114		}
115	}
116}
117
118func TestResolveMultipleAdjacent(t *testing.T) {
119	ctx := context.Background()
120	resolver := makeResolver()
121
122	addrs, err := resolver.Resolve(ctx, ma.StringCast("/dns4/example.com/dns6/example.com"))
123	if err != nil {
124		t.Error(err)
125	}
126	for i, x := range []ma.Multiaddr{ip4ma, ip4mb} {
127		for j, y := range []ma.Multiaddr{ip6ma, ip6mb} {
128			expected := ma.Join(x, y)
129			actual := addrs[i*2+j]
130			if !expected.Equal(actual) {
131				t.Fatalf("expected %s, got %s", expected, actual)
132			}
133		}
134	}
135}
136
137func TestResolveMultipleSandwitch(t *testing.T) {
138	ctx := context.Background()
139	resolver := makeResolver()
140
141	addrs, err := resolver.Resolve(ctx, ma.StringCast("/quic/dns4/example.com/dns6/example.com/http"))
142	if err != nil {
143		t.Error(err)
144	}
145	for i, x := range []ma.Multiaddr{ip4ma, ip4mb} {
146		for j, y := range []ma.Multiaddr{ip6ma, ip6mb} {
147			expected := ma.Join(ma.StringCast("/quic"), x, y, ma.StringCast("/http"))
148			actual := addrs[i*2+j]
149			if !expected.Equal(actual) {
150				t.Fatalf("expected %s, got %s", expected, actual)
151			}
152		}
153	}
154}
155
156func TestSimpleTXTResolve(t *testing.T) {
157	ctx := context.Background()
158	resolver := makeResolver()
159
160	addrs, err := resolver.Resolve(ctx, ma.StringCast("/dnsaddr/example.com"))
161	if err != nil {
162		t.Error(err)
163	}
164	if len(addrs) != 2 || !addrs[0].Equal(ip4ma) || addrs[0].Equal(ip6ma) {
165		t.Fatalf("expected [%s %s], got %+v", ip4ma, ip6ma, addrs)
166	}
167}
168
169func TestNonResolvable(t *testing.T) {
170	ctx := context.Background()
171	resolver := makeResolver()
172
173	addrs, err := resolver.Resolve(ctx, ip4ma)
174	if err != nil {
175		t.Error(err)
176	}
177	if len(addrs) != 1 || !addrs[0].Equal(ip4ma) {
178		t.Fatalf("expected [%s], got %+v", ip4ma, addrs)
179	}
180}
181
182func TestLongMatch(t *testing.T) {
183	ctx := context.Background()
184	resolver := makeResolver()
185
186	res, err := resolver.Resolve(ctx, ma.StringCast("/dnsaddr/example.com/quic/quic/quic/quic"))
187	if err != nil {
188		t.Error(err)
189	}
190	if len(res) != 0 {
191		t.Error("expected no results")
192	}
193}
194
195func TestEmptyResult(t *testing.T) {
196	ctx := context.Background()
197	resolver := makeResolver()
198
199	addrs, err := resolver.Resolve(ctx, ma.StringCast("/dnsaddr/none.com"))
200	if err != nil {
201		t.Error(err)
202	}
203	if len(addrs) > 0 {
204		t.Fatalf("expected [], got %+v", addrs)
205	}
206}
207
208func TestDnsaddrMatching(t *testing.T) {
209	ctx := context.Background()
210	resolver := makeResolver()
211
212	addrs, err := resolver.Resolve(ctx, ma.StringCast("/dnsaddr/matching.com/tcp/123/http"))
213	if err != nil {
214		t.Error(err)
215	}
216	if len(addrs) != 1 || !addrs[0].Equal(txtmc) {
217		t.Fatalf("expected [%s], got %+v", txtmc, addrs)
218	}
219
220	addrs, err = resolver.Resolve(ctx, ma.StringCast("/dnsaddr/matching.com/tcp/123"))
221	if err != nil {
222		t.Error(err)
223	}
224	if len(addrs) != 1 || !addrs[0].Equal(txtmd) {
225		t.Fatalf("expected [%s], got %+v", txtmd, addrs)
226	}
227}
228
229func TestBadDomain(t *testing.T) {
230	bts := ma.StringCast("/dns4/example.com").Bytes()
231	bts[len(bts)-5] = '/'
232	_, err := ma.NewMultiaddrBytes(bts)
233	if err == nil {
234		t.Error("expected malformed address to fail to parse")
235	}
236}
237