1
1
package autonat
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
6
+ "math/rand"
7
+ "net"
5
8
"sync"
6
9
"time"
7
10
@@ -24,8 +27,11 @@ const P_CIRCUIT = 290
24
27
var (
25
28
AutoNATServiceDialTimeout = 15 * time .Second
26
29
AutoNATServiceResetInterval = 1 * time .Minute
30
+ AutoNATServiceResetJitter = 15 * time .Second
27
31
28
- AutoNATServiceThrottle = 3
32
+ AutoNATServiceThrottle = 3
33
+ AutoNATGlobalThrottle = 30
34
+ AutoNATMaxPeerAddresses = 4
29
35
)
30
36
31
37
// AutoNATService provides NAT autodetection services to other peers
@@ -34,8 +40,9 @@ type AutoNATService struct {
34
40
dialer host.Host
35
41
36
42
// rate limiter
37
- mx sync.Mutex
38
- reqs map [peer.ID ]int
43
+ mx sync.Mutex
44
+ reqs map [peer.ID ]int
45
+ globalReqs int
39
46
}
40
47
41
48
// NewAutoNATService creates a new AutoNATService instance attached to a host
@@ -96,6 +103,21 @@ func (as *AutoNATService) handleStream(s network.Stream) {
96
103
}
97
104
}
98
105
106
+ // Optimistically extract the net.IP host from a multiaddress.
107
+ func addrToIP (addr ma.Multiaddr ) net.IP {
108
+ if v4 , err := addr .ValueForProtocol (ma .P_IP4 ); err == nil {
109
+ if c , err := ma .NewComponent (ma .ProtocolWithCode (ma .P_IP4 ).Name , v4 ); err == nil {
110
+ return net .IP (c .RawValue ())
111
+ }
112
+ }
113
+ if v6 , err := addr .ValueForProtocol (ma .P_IP6 ); err == nil {
114
+ if c , err := ma .NewComponent (ma .ProtocolWithCode (ma .P_IP6 ).Name , v6 ); err == nil {
115
+ return net .IP (c .RawValue ())
116
+ }
117
+ }
118
+ return nil
119
+ }
120
+
99
121
func (as * AutoNATService ) handleDial (p peer.ID , obsaddr ma.Multiaddr , mpi * pb.Message_PeerInfo ) * pb.Message_DialResponse {
100
122
if mpi == nil {
101
123
return newDialResponseError (pb .Message_E_BAD_REQUEST , "missing peer info" )
@@ -113,13 +135,15 @@ func (as *AutoNATService) handleDial(p peer.ID, obsaddr ma.Multiaddr, mpi *pb.Me
113
135
}
114
136
}
115
137
116
- addrs := make ([]ma.Multiaddr , 0 )
138
+ addrs := make ([]ma.Multiaddr , 0 , AutoNATMaxPeerAddresses )
117
139
seen := make (map [string ]struct {})
118
140
119
141
// add observed addr to the list of addresses to dial
142
+ var obsHost net.IP
120
143
if ! as .skipDial (obsaddr ) {
121
144
addrs = append (addrs , obsaddr )
122
145
seen [obsaddr .String ()] = struct {}{}
146
+ obsHost = addrToIP (obsaddr )
123
147
}
124
148
125
149
for _ , maddr := range mpi .GetAddrs () {
@@ -129,10 +153,22 @@ func (as *AutoNATService) handleDial(p peer.ID, obsaddr ma.Multiaddr, mpi *pb.Me
129
153
continue
130
154
}
131
155
156
+ if len (addrs ) >= AutoNATMaxPeerAddresses {
157
+ continue
158
+ }
159
+
132
160
if as .skipDial (addr ) {
133
161
continue
134
162
}
135
163
164
+ if err != nil {
165
+ log .Debugf ("Unexpected public, non-IP multiaddr: %s" , err )
166
+ continue
167
+ }
168
+ if ! bytes .Equal (obsHost , addrToIP (addr )) {
169
+ continue
170
+ }
171
+
136
172
str := addr .String ()
137
173
_ , ok := seen [str ]
138
174
if ok {
@@ -169,16 +205,19 @@ func (as *AutoNATService) doDial(pi peer.AddrInfo) *pb.Message_DialResponse {
169
205
// rate limit check
170
206
as .mx .Lock ()
171
207
count := as .reqs [pi .ID ]
172
- if count >= AutoNATServiceThrottle {
208
+ if count >= AutoNATServiceThrottle || as . globalReqs >= AutoNATGlobalThrottle {
173
209
as .mx .Unlock ()
174
210
return newDialResponseError (pb .Message_E_DIAL_REFUSED , "too many dials" )
175
211
}
176
212
as .reqs [pi .ID ] = count + 1
213
+ as .globalReqs ++
177
214
as .mx .Unlock ()
178
215
179
216
ctx , cancel := context .WithTimeout (as .ctx , AutoNATServiceDialTimeout )
180
217
defer cancel ()
181
218
219
+ as .dialer .Peerstore ().ClearAddrs (pi .ID )
220
+
182
221
err := as .dialer .Connect (ctx , pi )
183
222
if err != nil {
184
223
log .Debugf ("error dialing %s: %s" , pi .ID .Pretty (), err .Error ())
@@ -200,16 +239,18 @@ func (as *AutoNATService) doDial(pi peer.AddrInfo) *pb.Message_DialResponse {
200
239
}
201
240
202
241
func (as * AutoNATService ) resetRateLimiter () {
203
- ticker := time .NewTicker (AutoNATServiceResetInterval )
204
- defer ticker .Stop ()
242
+ timer := time .NewTimer (AutoNATServiceResetInterval )
243
+ defer timer .Stop ()
205
244
206
245
for {
207
246
select {
208
- case <- ticker .C :
247
+ case <- timer .C :
209
248
as .mx .Lock ()
210
249
as .reqs = make (map [peer.ID ]int )
250
+ as .globalReqs = 0
211
251
as .mx .Unlock ()
212
-
252
+ jitter := rand .Float32 () * float32 (AutoNATServiceResetJitter )
253
+ timer .Reset (AutoNATServiceResetInterval + time .Duration (int64 (jitter )))
213
254
case <- as .ctx .Done ():
214
255
return
215
256
}
0 commit comments