Skip to content

Commit eb41702

Browse files
Merge remote-tracking branch 'p2p/host/autonat/master' into merge-repo
2 parents 5155c77 + c63fd46 commit eb41702

18 files changed

+3192
-0
lines changed

p2p/host/autonat/autonat.go

+468
Large diffs are not rendered by default.

p2p/host/autonat/autonat_test.go

+298
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
package autonat
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
"github.com/libp2p/go-libp2p-core/event"
9+
"github.com/libp2p/go-libp2p-core/host"
10+
"github.com/libp2p/go-libp2p-core/network"
11+
"github.com/libp2p/go-libp2p-core/peer"
12+
13+
pb "github.com/libp2p/go-libp2p-autonat/pb"
14+
15+
bhost "github.com/libp2p/go-libp2p-blankhost"
16+
swarmt "github.com/libp2p/go-libp2p-swarm/testing"
17+
"github.com/libp2p/go-msgio/protoio"
18+
ma "github.com/multiformats/go-multiaddr"
19+
"github.com/stretchr/testify/require"
20+
)
21+
22+
// these are mock service implementations for testing
23+
func makeAutoNATServicePrivate(t *testing.T) host.Host {
24+
h := bhost.NewBlankHost(swarmt.GenSwarm(t))
25+
h.SetStreamHandler(AutoNATProto, sayPrivateStreamHandler(t))
26+
return h
27+
}
28+
29+
func sayPrivateStreamHandler(t *testing.T) network.StreamHandler {
30+
return func(s network.Stream) {
31+
defer s.Close()
32+
r := protoio.NewDelimitedReader(s, network.MessageSizeMax)
33+
if err := r.ReadMsg(&pb.Message{}); err != nil {
34+
t.Error(err)
35+
return
36+
}
37+
w := protoio.NewDelimitedWriter(s)
38+
res := pb.Message{
39+
Type: pb.Message_DIAL_RESPONSE.Enum(),
40+
DialResponse: newDialResponseError(pb.Message_E_DIAL_ERROR, "no dialable addresses"),
41+
}
42+
w.WriteMsg(&res)
43+
}
44+
}
45+
46+
func makeAutoNATServicePublic(t *testing.T) host.Host {
47+
h := bhost.NewBlankHost(swarmt.GenSwarm(t))
48+
h.SetStreamHandler(AutoNATProto, func(s network.Stream) {
49+
defer s.Close()
50+
r := protoio.NewDelimitedReader(s, network.MessageSizeMax)
51+
if err := r.ReadMsg(&pb.Message{}); err != nil {
52+
t.Error(err)
53+
return
54+
}
55+
w := protoio.NewDelimitedWriter(s)
56+
res := pb.Message{
57+
Type: pb.Message_DIAL_RESPONSE.Enum(),
58+
DialResponse: newDialResponseOK(s.Conn().RemoteMultiaddr()),
59+
}
60+
w.WriteMsg(&res)
61+
})
62+
return h
63+
}
64+
65+
func makeAutoNAT(t *testing.T, ash host.Host) (host.Host, AutoNAT) {
66+
h := bhost.NewBlankHost(swarmt.GenSwarm(t))
67+
h.Peerstore().AddAddrs(ash.ID(), ash.Addrs(), time.Minute)
68+
h.Peerstore().AddProtocols(ash.ID(), AutoNATProto)
69+
a, _ := New(h, WithSchedule(100*time.Millisecond, time.Second), WithoutStartupDelay())
70+
a.(*AmbientAutoNAT).config.dialPolicy.allowSelfDials = true
71+
a.(*AmbientAutoNAT).config.throttlePeerPeriod = 100 * time.Millisecond
72+
return h, a
73+
}
74+
75+
func identifyAsServer(server, recip host.Host) {
76+
recip.Peerstore().AddAddrs(server.ID(), server.Addrs(), time.Minute)
77+
recip.Peerstore().AddProtocols(server.ID(), AutoNATProto)
78+
79+
}
80+
81+
func connect(t *testing.T, a, b host.Host) {
82+
pinfo := peer.AddrInfo{ID: a.ID(), Addrs: a.Addrs()}
83+
err := b.Connect(context.Background(), pinfo)
84+
if err != nil {
85+
t.Fatal(err)
86+
}
87+
}
88+
89+
func expectEvent(t *testing.T, s event.Subscription, expected network.Reachability) {
90+
select {
91+
case e := <-s.Out():
92+
ev, ok := e.(event.EvtLocalReachabilityChanged)
93+
if !ok || ev.Reachability != expected {
94+
t.Fatal("got wrong event type from the bus")
95+
}
96+
97+
case <-time.After(100 * time.Millisecond):
98+
t.Fatal("failed to get the reachability event from the bus")
99+
}
100+
}
101+
102+
// tests
103+
func TestAutoNATPrivate(t *testing.T) {
104+
hs := makeAutoNATServicePrivate(t)
105+
defer hs.Close()
106+
hc, an := makeAutoNAT(t, hs)
107+
defer hc.Close()
108+
defer an.Close()
109+
110+
// subscribe to AutoNat events
111+
s, err := hc.EventBus().Subscribe(&event.EvtLocalReachabilityChanged{})
112+
if err != nil {
113+
t.Fatalf("failed to subscribe to event EvtLocalReachabilityChanged, err=%s", err)
114+
}
115+
116+
status := an.Status()
117+
if status != network.ReachabilityUnknown {
118+
t.Fatalf("unexpected NAT status: %d", status)
119+
}
120+
121+
connect(t, hs, hc)
122+
require.Eventually(t,
123+
func() bool { return an.Status() == network.ReachabilityPrivate },
124+
2*time.Second,
125+
25*time.Millisecond,
126+
"expected NAT status to be private",
127+
)
128+
expectEvent(t, s, network.ReachabilityPrivate)
129+
}
130+
131+
func TestAutoNATPublic(t *testing.T) {
132+
hs := makeAutoNATServicePublic(t)
133+
defer hs.Close()
134+
hc, an := makeAutoNAT(t, hs)
135+
defer hc.Close()
136+
defer an.Close()
137+
138+
// subscribe to AutoNat events
139+
s, err := hc.EventBus().Subscribe(&event.EvtLocalReachabilityChanged{})
140+
if err != nil {
141+
t.Fatalf("failed to subscribe to event EvtLocalReachabilityChanged, err=%s", err)
142+
}
143+
144+
status := an.Status()
145+
if status != network.ReachabilityUnknown {
146+
t.Fatalf("unexpected NAT status: %d", status)
147+
}
148+
149+
connect(t, hs, hc)
150+
require.Eventually(t,
151+
func() bool { return an.Status() == network.ReachabilityPublic },
152+
2*time.Second,
153+
25*time.Millisecond,
154+
"expected NAT status to be public",
155+
)
156+
157+
expectEvent(t, s, network.ReachabilityPublic)
158+
}
159+
160+
func TestAutoNATPublictoPrivate(t *testing.T) {
161+
hs := makeAutoNATServicePublic(t)
162+
defer hs.Close()
163+
hc, an := makeAutoNAT(t, hs)
164+
defer hc.Close()
165+
defer an.Close()
166+
167+
// subscribe to AutoNat events
168+
s, err := hc.EventBus().Subscribe(&event.EvtLocalReachabilityChanged{})
169+
if err != nil {
170+
t.Fatalf("failed to subscribe to event EvtLocalRoutabilityPublic, err=%s", err)
171+
}
172+
173+
if status := an.Status(); status != network.ReachabilityUnknown {
174+
t.Fatalf("unexpected NAT status: %d", status)
175+
}
176+
177+
connect(t, hs, hc)
178+
require.Eventually(t,
179+
func() bool { return an.Status() == network.ReachabilityPublic },
180+
2*time.Second,
181+
25*time.Millisecond,
182+
"expected NAT status to be public",
183+
)
184+
expectEvent(t, s, network.ReachabilityPublic)
185+
186+
hs.SetStreamHandler(AutoNATProto, sayPrivateStreamHandler(t))
187+
hps := makeAutoNATServicePrivate(t)
188+
connect(t, hps, hc)
189+
identifyAsServer(hps, hc)
190+
191+
require.Eventually(t,
192+
func() bool { return an.Status() == network.ReachabilityPrivate },
193+
2*time.Second,
194+
25*time.Millisecond,
195+
"expected NAT status to be private",
196+
)
197+
expectEvent(t, s, network.ReachabilityPrivate)
198+
}
199+
200+
func TestAutoNATIncomingEvents(t *testing.T) {
201+
hs := makeAutoNATServicePrivate(t)
202+
defer hs.Close()
203+
hc, ani := makeAutoNAT(t, hs)
204+
defer hc.Close()
205+
defer ani.Close()
206+
an := ani.(*AmbientAutoNAT)
207+
208+
status := an.Status()
209+
if status != network.ReachabilityUnknown {
210+
t.Fatalf("unexpected NAT status: %d", status)
211+
}
212+
213+
connect(t, hs, hc)
214+
215+
em, _ := hc.EventBus().Emitter(&event.EvtPeerIdentificationCompleted{})
216+
em.Emit(event.EvtPeerIdentificationCompleted{Peer: hs.ID()})
217+
218+
time.Sleep(10 * time.Millisecond)
219+
if an.Status() == network.ReachabilityUnknown {
220+
t.Fatalf("Expected probe due to identification of autonat service")
221+
}
222+
}
223+
224+
func TestAutoNATObservationRecording(t *testing.T) {
225+
hs := makeAutoNATServicePublic(t)
226+
defer hs.Close()
227+
hc, ani := makeAutoNAT(t, hs)
228+
defer hc.Close()
229+
defer ani.Close()
230+
an := ani.(*AmbientAutoNAT)
231+
232+
s, err := hc.EventBus().Subscribe(&event.EvtLocalReachabilityChanged{})
233+
if err != nil {
234+
t.Fatalf("failed to subscribe to event EvtLocalRoutabilityPublic, err=%s", err)
235+
}
236+
237+
// pubic observation without address should be ignored.
238+
an.recordObservation(autoNATResult{network.ReachabilityPublic, nil})
239+
if an.Status() != network.ReachabilityUnknown {
240+
t.Fatalf("unexpected transition")
241+
}
242+
243+
select {
244+
case <-s.Out():
245+
t.Fatal("not expecting a public reachability event")
246+
default:
247+
// expected
248+
}
249+
250+
addr, _ := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
251+
an.recordObservation(autoNATResult{network.ReachabilityPublic, addr})
252+
if an.Status() != network.ReachabilityPublic {
253+
t.Fatalf("failed to transition to public.")
254+
}
255+
256+
expectEvent(t, s, network.ReachabilityPublic)
257+
258+
// a single recording should have confidence still at 0, and transition to private quickly.
259+
an.recordObservation(autoNATResult{network.ReachabilityPrivate, nil})
260+
if an.Status() != network.ReachabilityPrivate {
261+
t.Fatalf("failed to transition to private.")
262+
}
263+
264+
expectEvent(t, s, network.ReachabilityPrivate)
265+
266+
// stronger public confidence should be harder to undo.
267+
an.recordObservation(autoNATResult{network.ReachabilityPublic, addr})
268+
an.recordObservation(autoNATResult{network.ReachabilityPublic, addr})
269+
if an.Status() != network.ReachabilityPublic {
270+
t.Fatalf("failed to transition to public.")
271+
}
272+
273+
expectEvent(t, s, network.ReachabilityPublic)
274+
275+
an.recordObservation(autoNATResult{network.ReachabilityPrivate, nil})
276+
if an.Status() != network.ReachabilityPublic {
277+
t.Fatalf("too-extreme private transition.")
278+
}
279+
280+
}
281+
282+
func TestStaticNat(t *testing.T) {
283+
_, cancel := context.WithCancel(context.Background())
284+
defer cancel()
285+
286+
h := bhost.NewBlankHost(swarmt.GenSwarm(t))
287+
defer h.Close()
288+
s, _ := h.EventBus().Subscribe(&event.EvtLocalReachabilityChanged{})
289+
290+
nat, err := New(h, WithReachability(network.ReachabilityPrivate))
291+
if err != nil {
292+
t.Fatal(err)
293+
}
294+
if nat.Status() != network.ReachabilityPrivate {
295+
t.Fatalf("should be private")
296+
}
297+
expectEvent(t, s, network.ReachabilityPrivate)
298+
}

0 commit comments

Comments
 (0)