libp2p 2.3.1-0862522fe → 2.3.1-2c182d2e2

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.
@@ -1,3 +1,4 @@
1
+ import { isIPv4 } from '@chainsafe/is-ip'
1
2
  import { peerIdFromString } from '@libp2p/peer-id'
2
3
  import { debounce } from '@libp2p/utils/debounce'
3
4
  import { multiaddr, protocols } from '@multiformats/multiaddr'
@@ -78,6 +79,18 @@ const CODEC_IP4 = 0x04
78
79
  const CODEC_IP6 = 0x29
79
80
  const CODEC_DNS4 = 0x36
80
81
  const CODEC_DNS6 = 0x37
82
+ const CODEC_TCP = 0x06
83
+ const CODEC_UDP = 0x0111
84
+
85
+ interface PublicAddressMapping {
86
+ externalIp: string
87
+ externalPort: number
88
+ }
89
+
90
+ interface DNSMapping {
91
+ domain: string
92
+ confident: boolean
93
+ }
81
94
 
82
95
  export class AddressManager implements AddressManagerInterface {
83
96
  private readonly log: Logger
@@ -88,7 +101,8 @@ export class AddressManager implements AddressManagerInterface {
88
101
  private readonly appendAnnounce: Set<string>
89
102
  private readonly observed: Map<string, ObservedAddressMetadata>
90
103
  private readonly announceFilter: AddressFilter
91
- private readonly ipDomainMappings: Map<string, string>
104
+ private readonly ipDomainMappings: Map<string, DNSMapping>
105
+ private readonly publicAddressMappings: Map<string, PublicAddressMapping[]>
92
106
 
93
107
  /**
94
108
  * Responsible for managing the peer addresses.
@@ -106,6 +120,7 @@ export class AddressManager implements AddressManagerInterface {
106
120
  this.appendAnnounce = new Set(appendAnnounce.map(ma => ma.toString()))
107
121
  this.observed = new Map()
108
122
  this.ipDomainMappings = new Map()
123
+ this.publicAddressMappings = new Map()
109
124
  this.announceFilter = init.announceFilter ?? defaultAddressFilter
110
125
 
111
126
  // this method gets called repeatedly on startup when transports start listening so
@@ -127,13 +142,8 @@ export class AddressManager implements AddressManagerInterface {
127
142
  _updatePeerStoreAddresses (): void {
128
143
  // if announce addresses have been configured, ensure they make it into our peer
129
144
  // record for things like identify
130
- const addrs = this.getAnnounceAddrs()
131
- .concat(this.components.transportManager.getAddrs())
132
- .concat(
133
- [...this.observed.entries()]
134
- .filter(([_, metadata]) => metadata.confident)
135
- .map(([str]) => multiaddr(str))
136
- ).map(ma => {
145
+ const addrs = this.getAddresses()
146
+ .map(ma => {
137
147
  // strip our peer id if it is present
138
148
  if (ma.getPeerId() === this.components.peerId.toString()) {
139
149
  return ma.decapsulate(`/p2p/${this.components.peerId.toString()}`)
@@ -145,7 +155,9 @@ export class AddressManager implements AddressManagerInterface {
145
155
  this.components.peerStore.patch(this.components.peerId, {
146
156
  multiaddrs: addrs
147
157
  })
148
- .catch(err => { this.log.error('error updating addresses', err) })
158
+ .catch(err => {
159
+ this.log.error('error updating addresses', err)
160
+ })
149
161
  }
150
162
 
151
163
  /**
@@ -239,14 +251,59 @@ export class AddressManager implements AddressManagerInterface {
239
251
  .map(([ma]) => multiaddr(ma))
240
252
  )
241
253
 
242
- const mappedMultiaddrs: Multiaddr[] = []
254
+ // add public addresses
255
+ const ipMappedMultiaddrs: Multiaddr[] = []
256
+ multiaddrs.forEach(ma => {
257
+ const tuples = ma.stringTuples()
258
+ let tuple: string | undefined
259
+
260
+ // see if the internal host/port/protocol tuple has been mapped externally
261
+ if ((tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) && tuples[1][0] === CODEC_TCP) {
262
+ tuple = `${tuples[0][1]}-${tuples[1][1]}-tcp`
263
+ } else if ((tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) && tuples[1][0] === CODEC_UDP) {
264
+ tuple = `${tuples[0][1]}-${tuples[1][1]}-udp`
265
+ }
266
+
267
+ if (tuple == null) {
268
+ return
269
+ }
270
+
271
+ const mappings = this.publicAddressMappings.get(tuple)
272
+
273
+ if (mappings == null) {
274
+ return
275
+ }
276
+
277
+ for (const mapping of mappings) {
278
+ tuples[0][0] = isIPv4(mapping.externalIp) ? CODEC_IP4 : CODEC_IP6
279
+ tuples[0][1] = mapping.externalIp
280
+ tuples[1][1] = `${mapping.externalPort}`
281
+
282
+ ipMappedMultiaddrs.push(
283
+ multiaddr(`/${
284
+ tuples.map(tuple => {
285
+ return [
286
+ protocols(tuple[0]).name,
287
+ tuple[1]
288
+ ].join('/')
289
+ }).join('/')
290
+ }`)
291
+ )
292
+ }
293
+ })
294
+ multiaddrs = multiaddrs.concat(ipMappedMultiaddrs)
243
295
 
244
296
  // add ip->domain mappings
297
+ const dnsMappedMultiaddrs: Multiaddr[] = []
245
298
  for (const ma of multiaddrs) {
246
- const tuples = [...ma.stringTuples()]
299
+ const tuples = ma.stringTuples()
247
300
  let mappedIp = false
248
301
 
249
- for (const [ip, domain] of this.ipDomainMappings.entries()) {
302
+ for (const [ip, mapping] of this.ipDomainMappings.entries()) {
303
+ if (!mapping.confident) {
304
+ continue
305
+ }
306
+
250
307
  for (let i = 0; i < tuples.length; i++) {
251
308
  if (tuples[i][1] !== ip) {
252
309
  continue
@@ -254,20 +311,20 @@ export class AddressManager implements AddressManagerInterface {
254
311
 
255
312
  if (tuples[i][0] === CODEC_IP4) {
256
313
  tuples[i][0] = CODEC_DNS4
257
- tuples[i][1] = domain
314
+ tuples[i][1] = mapping.domain
258
315
  mappedIp = true
259
316
  }
260
317
 
261
318
  if (tuples[i][0] === CODEC_IP6) {
262
319
  tuples[i][0] = CODEC_DNS6
263
- tuples[i][1] = domain
320
+ tuples[i][1] = mapping.domain
264
321
  mappedIp = true
265
322
  }
266
323
  }
267
324
  }
268
325
 
269
326
  if (mappedIp) {
270
- mappedMultiaddrs.push(
327
+ dnsMappedMultiaddrs.push(
271
328
  multiaddr(`/${
272
329
  tuples.map(tuple => {
273
330
  return [
@@ -279,8 +336,7 @@ export class AddressManager implements AddressManagerInterface {
279
336
  )
280
337
  }
281
338
  }
282
-
283
- multiaddrs = multiaddrs.concat(mappedMultiaddrs)
339
+ multiaddrs = multiaddrs.concat(dnsMappedMultiaddrs)
284
340
 
285
341
  // dedupe multiaddrs
286
342
  const addrSet = new Set<string>()
@@ -318,15 +374,66 @@ export class AddressManager implements AddressManagerInterface {
318
374
 
319
375
  addDNSMapping (domain: string, addresses: string[]): void {
320
376
  addresses.forEach(ip => {
321
- this.ipDomainMappings.set(ip, domain)
377
+ this.log('add DNS mapping %s to %s', ip, domain)
378
+
379
+ // check ip/public ip mappings to see if we think we are contactable
380
+ const confident = [...this.publicAddressMappings.entries()].some(([key, mappings]) => {
381
+ return mappings.some(mapping => mapping.externalIp === ip)
382
+ })
383
+
384
+ this.ipDomainMappings.set(ip, {
385
+ domain,
386
+ confident
387
+ })
322
388
  })
389
+ this._updatePeerStoreAddresses()
323
390
  }
324
391
 
325
392
  removeDNSMapping (domain: string): void {
326
- for (const [key, value] of this.ipDomainMappings.entries()) {
327
- if (value === domain) {
393
+ for (const [key, mapping] of this.ipDomainMappings.entries()) {
394
+ if (mapping.domain === domain) {
395
+ this.log('remove DNS mapping for %s', domain)
328
396
  this.ipDomainMappings.delete(key)
329
397
  }
330
398
  }
399
+ this._updatePeerStoreAddresses()
400
+ }
401
+
402
+ addPublicAddressMapping (internalIp: string, internalPort: number, externalIp: string, externalPort: number = internalPort, protocol: 'tcp' | 'udp' = 'tcp'): void {
403
+ const key = `${internalIp}-${internalPort}-${protocol}`
404
+ const mappings = this.publicAddressMappings.get(key) ?? []
405
+ mappings.push({
406
+ externalIp,
407
+ externalPort
408
+ })
409
+
410
+ this.publicAddressMappings.set(key, mappings)
411
+
412
+ // update domain mappings to indicate we are now confident that any matching
413
+ // ip/domain combination can now be resolved externally
414
+ for (const [key, mapping] of this.ipDomainMappings.entries()) {
415
+ if (key === externalIp) {
416
+ mapping.confident = true
417
+
418
+ this.ipDomainMappings.set(key, mapping)
419
+ }
420
+ }
421
+
422
+ this._updatePeerStoreAddresses()
423
+ }
424
+
425
+ removePublicAddressMapping (internalIp: string, internalPort: number, externalIp: string, externalPort: number = internalPort, protocol: 'tcp' | 'udp' = 'tcp'): void {
426
+ const key = `${internalIp}-${internalPort}-${protocol}`
427
+ const mappings = (this.publicAddressMappings.get(key) ?? []).filter(mapping => {
428
+ return mapping.externalIp !== externalIp && mapping.externalPort !== externalPort
429
+ })
430
+
431
+ if (mappings.length === 0) {
432
+ this.publicAddressMappings.delete(key)
433
+ } else {
434
+ this.publicAddressMappings.set(key, mappings)
435
+ }
436
+
437
+ this._updatePeerStoreAddresses()
331
438
  }
332
439
  }
@@ -1,19 +1,33 @@
1
1
  import { isPrivateIp } from '@libp2p/utils/private-ip'
2
+ import { WebSockets } from '@multiformats/multiaddr-matcher'
2
3
  import type { ConnectionGater } from '@libp2p/interface'
3
4
  import type { Multiaddr } from '@multiformats/multiaddr'
4
5
 
6
+ const CODEC_IP4 = 0x04
7
+ const CODEC_IP6 = 0x29
8
+
5
9
  /**
6
- * Returns a connection gater that disallows dialling private addresses by
7
- * default. Browsers are severely limited in their resource usage so don't
8
- * waste time trying to dial undiallable addresses.
10
+ * Returns a connection gater that disallows dialling private addresses or
11
+ * insecure websockets by default.
12
+ *
13
+ * Browsers are severely limited in their resource usage so don't waste time
14
+ * trying to dial undiallable addresses, and they also print verbose error
15
+ * messages when making connections over insecure transports which causes
16
+ * confusion.
9
17
  */
10
18
  export function connectionGater (gater: ConnectionGater = {}): ConnectionGater {
11
19
  return {
12
20
  denyDialPeer: async () => false,
13
21
  denyDialMultiaddr: async (multiaddr: Multiaddr) => {
22
+ // do not connect to insecure websockets by default
23
+ if (WebSockets.matches(multiaddr)) {
24
+ return false
25
+ }
26
+
14
27
  const tuples = multiaddr.stringTuples()
15
28
 
16
- if (tuples[0][0] === 4 || tuples[0][0] === 41) {
29
+ // do not connect to private addresses by default
30
+ if (tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) {
17
31
  return Boolean(isPrivateIp(`${tuples[0][1]}`))
18
32
  }
19
33
 
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable max-depth */
2
2
  import { TimeoutError, DialError, setMaxListeners, AbortError } from '@libp2p/interface'
3
3
  import { PeerMap } from '@libp2p/peer-collections'
4
- import { PriorityQueue, type PriorityQueueJobOptions } from '@libp2p/utils/priority-queue'
5
- import { type Multiaddr, type Resolver, resolvers, multiaddr } from '@multiformats/multiaddr'
4
+ import { PriorityQueue } from '@libp2p/utils/priority-queue'
5
+ import { resolvers, multiaddr } from '@multiformats/multiaddr'
6
6
  import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
7
7
  import { Circuit } from '@multiformats/multiaddr-matcher'
8
- import { type ClearableSignal, anySignal } from 'any-signal'
8
+ import { anySignal } from 'any-signal'
9
9
  import { CustomProgressEvent } from 'progress-events'
10
10
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
11
11
  import { DialDeniedError, NoValidAddressesError } from '../errors.js'
@@ -23,7 +23,9 @@ import { resolveMultiaddrs } from './utils.js'
23
23
  import { DEFAULT_DIAL_PRIORITY } from './index.js'
24
24
  import type { AddressSorter, ComponentLogger, Logger, Connection, ConnectionGater, Metrics, PeerId, Address, PeerStore, PeerRouting, IsDialableOptions, OpenConnectionProgressEvents } from '@libp2p/interface'
25
25
  import type { OpenConnectionOptions, TransportManager } from '@libp2p/interface-internal'
26
+ import type { PriorityQueueJobOptions } from '@libp2p/utils/priority-queue'
26
27
  import type { DNS } from '@multiformats/dns'
28
+ import type { Multiaddr, Resolver } from '@multiformats/multiaddr'
27
29
  import type { ProgressOptions } from 'progress-events'
28
30
 
29
31
  export interface PendingDialTarget {
@@ -204,7 +206,12 @@ export class DialQueue {
204
206
  options?.onProgress?.(new CustomProgressEvent('dial-queue:start-dial'))
205
207
  // create abort conditions - need to do this before `calculateMultiaddrs` as
206
208
  // we may be about to resolve a dns addr which can time out
207
- const signal = this.createDialAbortController(options?.signal)
209
+ const signal = anySignal([
210
+ this.shutDownController.signal,
211
+ options.signal
212
+ ])
213
+ setMaxListeners(Infinity, signal)
214
+
208
215
  let addrsToDial: Address[]
209
216
 
210
217
  try {
@@ -299,25 +306,11 @@ export class DialQueue {
299
306
  peerId,
300
307
  priority: options.priority ?? DEFAULT_DIAL_PRIORITY,
301
308
  multiaddrs: new Set(multiaddrs.map(ma => ma.toString())),
302
- signal: options.signal,
309
+ signal: options.signal ?? AbortSignal.timeout(this.dialTimeout),
303
310
  onProgress: options.onProgress
304
311
  })
305
312
  }
306
313
 
307
- private createDialAbortController (userSignal?: AbortSignal): ClearableSignal {
308
- // let any signal abort the dial
309
- const signal = anySignal([
310
- AbortSignal.timeout(this.dialTimeout),
311
- this.shutDownController.signal,
312
- userSignal
313
- ])
314
-
315
- // This emitter gets listened to a lot
316
- setMaxListeners(Infinity, signal)
317
-
318
- return signal
319
- }
320
-
321
314
  // eslint-disable-next-line complexity
322
315
  private async calculateMultiaddrs (peerId?: PeerId, multiaddrs: Set<string> = new Set<string>(), options: OpenConnectionOptions = {}): Promise<Address[]> {
323
316
  const addrs: Address[] = [...multiaddrs].map(ma => ({
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '2.3.1-0862522fe'
2
- export const name = 'libp2p'
1
+ export const version = '2.3.1-2c182d2e2'
2
+ export const name = 'js-libp2p'
package/LICENSE DELETED
@@ -1,4 +0,0 @@
1
- This project is dual licensed under MIT and Apache-2.0.
2
-
3
- MIT: https://www.opensource.org/licenses/mit
4
- Apache-2.0: https://www.apache.org/licenses/license-2.0