@libp2p/autonat 1.0.21 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +1 -101
- package/dist/src/autonat.d.ts +1 -0
- package/dist/src/autonat.d.ts.map +1 -1
- package/dist/src/autonat.js +143 -149
- package/dist/src/autonat.js.map +1 -1
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/autonat.ts +154 -165
- package/src/index.ts +3 -3
package/src/autonat.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CodeError, ERR_TIMEOUT, setMaxListeners } from '@libp2p/interface'
|
|
2
2
|
import { peerIdFromBytes } from '@libp2p/peer-id'
|
|
3
|
-
import { createEd25519PeerId } from '@libp2p/peer-id-factory'
|
|
4
3
|
import { isPrivateIp } from '@libp2p/utils/private-ip'
|
|
5
4
|
import { multiaddr, protocols } from '@multiformats/multiaddr'
|
|
6
5
|
import first from 'it-first'
|
|
@@ -15,7 +14,7 @@ import {
|
|
|
15
14
|
} from './constants.js'
|
|
16
15
|
import { Message } from './pb/index.js'
|
|
17
16
|
import type { AutoNATComponents, AutoNATServiceInit } from './index.js'
|
|
18
|
-
import type { Logger, Connection, PeerId, PeerInfo, Startable } from '@libp2p/interface'
|
|
17
|
+
import type { Logger, Connection, PeerId, PeerInfo, Startable, AbortOptions } from '@libp2p/interface'
|
|
19
18
|
import type { IncomingStreamData } from '@libp2p/interface-internal'
|
|
20
19
|
|
|
21
20
|
// if more than 3 peers manage to dial us on what we believe to be our external
|
|
@@ -95,9 +94,6 @@ export class AutoNATService implements Startable {
|
|
|
95
94
|
// appearing in the console
|
|
96
95
|
setMaxListeners(Infinity, signal)
|
|
97
96
|
|
|
98
|
-
const ourHosts = this.components.addressManager.getAddresses()
|
|
99
|
-
.map(ma => ma.toOptions().host)
|
|
100
|
-
|
|
101
97
|
try {
|
|
102
98
|
const self = this
|
|
103
99
|
|
|
@@ -138,193 +134,188 @@ export class AutoNATService implements Startable {
|
|
|
138
134
|
return
|
|
139
135
|
}
|
|
140
136
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
yield Message.encode(await self.handleAutonatMessage(request, data.connection, {
|
|
138
|
+
signal
|
|
139
|
+
}))
|
|
140
|
+
},
|
|
141
|
+
(source) => lp.encode(source),
|
|
142
|
+
data.stream
|
|
143
|
+
)
|
|
144
|
+
} catch (err) {
|
|
145
|
+
this.log.error('error handling incoming autonat stream', err)
|
|
146
|
+
} finally {
|
|
147
|
+
signal.removeEventListener('abort', onAbort)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
145
150
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
})
|
|
151
|
+
_verifyExternalAddresses (): void {
|
|
152
|
+
void this.verifyExternalAddresses()
|
|
153
|
+
.catch(err => {
|
|
154
|
+
this.log.error('error verifying external address', err)
|
|
155
|
+
})
|
|
156
|
+
}
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
158
|
+
private async handleAutonatMessage (message: Message, connection: Connection, options?: AbortOptions): Promise<Message> {
|
|
159
|
+
const ourHosts = this.components.addressManager.getAddresses()
|
|
160
|
+
.map(ma => ma.toOptions().host)
|
|
156
161
|
|
|
157
|
-
|
|
158
|
-
const peer = dialRequest.peer
|
|
162
|
+
const dialRequest = message.dial
|
|
159
163
|
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
if (dialRequest == null) {
|
|
165
|
+
this.log.error('dial was missing from message')
|
|
162
166
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
return {
|
|
168
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
169
|
+
dialResponse: {
|
|
170
|
+
status: Message.ResponseStatus.E_BAD_REQUEST,
|
|
171
|
+
statusText: 'No Dial message found in message'
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
170
175
|
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
let peerId: PeerId
|
|
177
|
+
const peer = dialRequest.peer
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
} catch (err) {
|
|
177
|
-
self.log.error('invalid PeerId', err)
|
|
179
|
+
if (peer == null || peer.id == null) {
|
|
180
|
+
this.log.error('PeerId missing from message')
|
|
178
181
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
return {
|
|
183
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
184
|
+
dialResponse: {
|
|
185
|
+
status: Message.ResponseStatus.E_BAD_REQUEST,
|
|
186
|
+
statusText: 'missing peer info'
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
186
190
|
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
try {
|
|
192
|
+
peerId = peerIdFromBytes(peer.id)
|
|
193
|
+
} catch (err) {
|
|
194
|
+
this.log.error('invalid PeerId', err)
|
|
189
195
|
|
|
190
|
-
|
|
196
|
+
return {
|
|
197
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
198
|
+
dialResponse: {
|
|
199
|
+
status: Message.ResponseStatus.E_BAD_REQUEST,
|
|
200
|
+
statusText: 'bad peer id'
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
191
204
|
|
|
192
|
-
|
|
193
|
-
if (!data.connection.remotePeer.equals(peerId)) {
|
|
194
|
-
self.log('target peer %p did not equal sending peer %p', peerId, data.connection.remotePeer)
|
|
205
|
+
this.log('incoming request from %p', peerId)
|
|
195
206
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
status: Message.ResponseStatus.E_BAD_REQUEST,
|
|
200
|
-
statusText: 'peer id mismatch'
|
|
201
|
-
}
|
|
202
|
-
})
|
|
207
|
+
// reject any dial requests that arrive via relays
|
|
208
|
+
if (!connection.remotePeer.equals(peerId)) {
|
|
209
|
+
this.log('target peer %p did not equal sending peer %p', peerId, connection.remotePeer)
|
|
203
210
|
|
|
204
|
-
|
|
205
|
-
|
|
211
|
+
return {
|
|
212
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
213
|
+
dialResponse: {
|
|
214
|
+
status: Message.ResponseStatus.E_BAD_REQUEST,
|
|
215
|
+
statusText: 'peer id mismatch'
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
206
219
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
220
|
+
// get a list of multiaddrs to dial
|
|
221
|
+
const multiaddrs = peer.addrs
|
|
222
|
+
.map(buf => multiaddr(buf))
|
|
223
|
+
.filter(ma => {
|
|
224
|
+
const isFromSameHost = ma.toOptions().host === connection.remoteAddr.toOptions().host
|
|
212
225
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
this.log.trace('request to dial %a was sent from %a is same host %s', ma, connection.remoteAddr, isFromSameHost)
|
|
227
|
+
// skip any Multiaddrs where the target node's IP does not match the sending node's IP
|
|
228
|
+
return isFromSameHost
|
|
229
|
+
})
|
|
230
|
+
.filter(ma => {
|
|
231
|
+
const host = ma.toOptions().host
|
|
232
|
+
const isPublicIp = !(isPrivateIp(host) ?? false)
|
|
220
233
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
234
|
+
this.log.trace('host %s was public %s', host, isPublicIp)
|
|
235
|
+
// don't try to dial private addresses
|
|
236
|
+
return isPublicIp
|
|
237
|
+
})
|
|
238
|
+
.filter(ma => {
|
|
239
|
+
const host = ma.toOptions().host
|
|
240
|
+
const isNotOurHost = !ourHosts.includes(host)
|
|
228
241
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
242
|
+
this.log.trace('host %s was not our host %s', host, isNotOurHost)
|
|
243
|
+
// don't try to dial nodes on the same host as us
|
|
244
|
+
return isNotOurHost
|
|
245
|
+
})
|
|
246
|
+
.filter(ma => {
|
|
247
|
+
const isSupportedTransport = Boolean(this.components.transportManager.dialTransportForMultiaddr(ma))
|
|
235
248
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
249
|
+
this.log.trace('transport for %a is supported %s', ma, isSupportedTransport)
|
|
250
|
+
// skip any Multiaddrs that have transports we do not support
|
|
251
|
+
return isSupportedTransport
|
|
252
|
+
})
|
|
253
|
+
.map(ma => {
|
|
254
|
+
if (ma.getPeerId() == null) {
|
|
255
|
+
// make sure we have the PeerId as part of the Multiaddr
|
|
256
|
+
ma = ma.encapsulate(`/p2p/${peerId.toString()}`)
|
|
257
|
+
}
|
|
245
258
|
|
|
246
|
-
|
|
247
|
-
|
|
259
|
+
return ma
|
|
260
|
+
})
|
|
248
261
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
262
|
+
// make sure we have something to dial
|
|
263
|
+
if (multiaddrs.length === 0) {
|
|
264
|
+
this.log('no valid multiaddrs for %p in message', peerId)
|
|
252
265
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
266
|
+
return {
|
|
267
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
268
|
+
dialResponse: {
|
|
269
|
+
status: Message.ResponseStatus.E_DIAL_REFUSED,
|
|
270
|
+
statusText: 'no dialable addresses'
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
260
274
|
|
|
261
|
-
|
|
262
|
-
}
|
|
275
|
+
this.log('dial multiaddrs %s for peer %p', multiaddrs.map(ma => ma.toString()).join(', '), peerId)
|
|
263
276
|
|
|
264
|
-
|
|
277
|
+
let errorMessage = ''
|
|
278
|
+
let lastMultiaddr = multiaddrs[0]
|
|
265
279
|
|
|
266
|
-
|
|
267
|
-
|
|
280
|
+
for await (const multiaddr of multiaddrs) {
|
|
281
|
+
let connection: Connection | undefined
|
|
282
|
+
lastMultiaddr = multiaddr
|
|
268
283
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
lastMultiaddr = multiaddr
|
|
284
|
+
try {
|
|
285
|
+
connection = await this.components.connectionManager.openConnection(multiaddr, options)
|
|
272
286
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
287
|
+
if (!connection.remoteAddr.equals(multiaddr)) {
|
|
288
|
+
this.log.error('tried to dial %a but dialed %a', multiaddr, connection.remoteAddr)
|
|
289
|
+
throw new Error('Unexpected remote address')
|
|
290
|
+
}
|
|
277
291
|
|
|
278
|
-
|
|
279
|
-
self.log.error('tried to dial %a but dialed %a', multiaddr, connection.remoteAddr)
|
|
280
|
-
throw new Error('Unexpected remote address')
|
|
281
|
-
}
|
|
292
|
+
this.log('Success %p', peerId)
|
|
282
293
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
status: Message.ResponseStatus.OK,
|
|
289
|
-
addr: connection.remoteAddr.decapsulateCode(protocols('p2p').code).bytes
|
|
290
|
-
}
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
return
|
|
294
|
-
} catch (err: any) {
|
|
295
|
-
self.log('could not dial %p', peerId, err)
|
|
296
|
-
errorMessage = err.message
|
|
297
|
-
} finally {
|
|
298
|
-
if (connection != null) {
|
|
299
|
-
await connection.close()
|
|
300
|
-
}
|
|
301
|
-
}
|
|
294
|
+
return {
|
|
295
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
296
|
+
dialResponse: {
|
|
297
|
+
status: Message.ResponseStatus.OK,
|
|
298
|
+
addr: connection.remoteAddr.decapsulateCode(protocols('p2p').code).bytes
|
|
302
299
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
},
|
|
313
|
-
(source) => lp.encode(source),
|
|
314
|
-
data.stream
|
|
315
|
-
)
|
|
316
|
-
} catch (err) {
|
|
317
|
-
this.log.error('error handling incoming autonat stream', err)
|
|
318
|
-
} finally {
|
|
319
|
-
signal.removeEventListener('abort', onAbort)
|
|
300
|
+
}
|
|
301
|
+
} catch (err: any) {
|
|
302
|
+
this.log('could not dial %p', peerId, err)
|
|
303
|
+
errorMessage = err.message
|
|
304
|
+
} finally {
|
|
305
|
+
if (connection != null) {
|
|
306
|
+
await connection.close()
|
|
307
|
+
}
|
|
308
|
+
}
|
|
320
309
|
}
|
|
321
|
-
}
|
|
322
310
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
311
|
+
return {
|
|
312
|
+
type: Message.MessageType.DIAL_RESPONSE,
|
|
313
|
+
dialResponse: {
|
|
314
|
+
status: Message.ResponseStatus.E_DIAL_ERROR,
|
|
315
|
+
statusText: errorMessage,
|
|
316
|
+
addr: lastMultiaddr.bytes
|
|
317
|
+
}
|
|
318
|
+
}
|
|
328
319
|
}
|
|
329
320
|
|
|
330
321
|
/**
|
|
@@ -374,9 +365,6 @@ export class AutoNATService implements Startable {
|
|
|
374
365
|
}
|
|
375
366
|
}
|
|
376
367
|
})
|
|
377
|
-
// find some random peers
|
|
378
|
-
const randomPeer = await createEd25519PeerId()
|
|
379
|
-
const randomCid = randomPeer.toBytes()
|
|
380
368
|
|
|
381
369
|
const results: Record<string, { success: number, failure: number }> = {}
|
|
382
370
|
const networkSegments: string[] = []
|
|
@@ -449,7 +437,8 @@ export class AutoNATService implements Startable {
|
|
|
449
437
|
}
|
|
450
438
|
}
|
|
451
439
|
|
|
452
|
-
|
|
440
|
+
// find some random peers
|
|
441
|
+
for await (const dialResponse of parallel(map(this.components.randomWalk.walk({
|
|
453
442
|
signal
|
|
454
443
|
}), (peer) => async () => verifyAddress(peer)), {
|
|
455
444
|
concurrency: REQUIRED_SUCCESSFUL_DIALS
|
package/src/index.ts
CHANGED
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import { AutoNATService } from './autonat.js'
|
|
34
|
-
import type { ComponentLogger, PeerId
|
|
35
|
-
import type { AddressManager, ConnectionManager, Registrar, TransportManager } from '@libp2p/interface-internal'
|
|
34
|
+
import type { ComponentLogger, PeerId } from '@libp2p/interface'
|
|
35
|
+
import type { AddressManager, ConnectionManager, RandomWalk, Registrar, TransportManager } from '@libp2p/interface-internal'
|
|
36
36
|
|
|
37
37
|
export interface AutoNATServiceInit {
|
|
38
38
|
/**
|
|
@@ -72,8 +72,8 @@ export interface AutoNATComponents {
|
|
|
72
72
|
transportManager: TransportManager
|
|
73
73
|
peerId: PeerId
|
|
74
74
|
connectionManager: ConnectionManager
|
|
75
|
-
peerRouting: PeerRouting
|
|
76
75
|
logger: ComponentLogger
|
|
76
|
+
randomWalk: RandomWalk
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
export function autoNAT (init: AutoNATServiceInit = {}): (components: AutoNATComponents) => unknown {
|