libp2p 2.3.1 → 2.4.0-127abe24b

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.
Files changed (69) hide show
  1. package/README.md +9 -25
  2. package/dist/index.min.js +18 -15
  3. package/dist/src/address-manager/dns-mappings.d.ts +20 -0
  4. package/dist/src/address-manager/dns-mappings.d.ts.map +1 -0
  5. package/dist/src/address-manager/dns-mappings.js +139 -0
  6. package/dist/src/address-manager/dns-mappings.js.map +1 -0
  7. package/dist/src/{address-manager.d.ts → address-manager/index.d.ts} +54 -10
  8. package/dist/src/address-manager/index.d.ts.map +1 -0
  9. package/dist/src/address-manager/index.js +264 -0
  10. package/dist/src/address-manager/index.js.map +1 -0
  11. package/dist/src/address-manager/ip-mappings.d.ts +18 -0
  12. package/dist/src/address-manager/ip-mappings.d.ts.map +1 -0
  13. package/dist/src/address-manager/ip-mappings.js +143 -0
  14. package/dist/src/address-manager/ip-mappings.js.map +1 -0
  15. package/dist/src/address-manager/observed-addresses.d.ts +19 -0
  16. package/dist/src/address-manager/observed-addresses.d.ts.map +1 -0
  17. package/dist/src/address-manager/observed-addresses.js +70 -0
  18. package/dist/src/address-manager/observed-addresses.js.map +1 -0
  19. package/dist/src/address-manager/transport-addresses.d.ts +19 -0
  20. package/dist/src/address-manager/transport-addresses.d.ts.map +1 -0
  21. package/dist/src/address-manager/transport-addresses.js +83 -0
  22. package/dist/src/address-manager/transport-addresses.js.map +1 -0
  23. package/dist/src/config/connection-gater.browser.d.ts +7 -3
  24. package/dist/src/config/connection-gater.browser.d.ts.map +1 -1
  25. package/dist/src/config/connection-gater.browser.js +16 -4
  26. package/dist/src/config/connection-gater.browser.js.map +1 -1
  27. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
  28. package/dist/src/connection-manager/connection-pruner.js +4 -3
  29. package/dist/src/connection-manager/connection-pruner.js.map +1 -1
  30. package/dist/src/connection-manager/dial-queue.d.ts +3 -3
  31. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
  32. package/dist/src/connection-manager/dial-queue.js +6 -13
  33. package/dist/src/connection-manager/dial-queue.js.map +1 -1
  34. package/dist/src/connection-manager/index.d.ts +1 -0
  35. package/dist/src/connection-manager/index.d.ts.map +1 -1
  36. package/dist/src/connection-manager/index.js +10 -6
  37. package/dist/src/connection-manager/index.js.map +1 -1
  38. package/dist/src/connection-manager/utils.d.ts +13 -1
  39. package/dist/src/connection-manager/utils.d.ts.map +1 -1
  40. package/dist/src/connection-manager/utils.js +33 -1
  41. package/dist/src/connection-manager/utils.js.map +1 -1
  42. package/dist/src/index.d.ts +1 -1
  43. package/dist/src/index.d.ts.map +1 -1
  44. package/dist/src/libp2p.js +1 -1
  45. package/dist/src/libp2p.js.map +1 -1
  46. package/dist/src/version.d.ts +2 -2
  47. package/dist/src/version.d.ts.map +1 -1
  48. package/dist/src/version.js +2 -2
  49. package/dist/src/version.js.map +1 -1
  50. package/package.json +27 -25
  51. package/src/address-manager/dns-mappings.ts +182 -0
  52. package/src/address-manager/index.ts +413 -0
  53. package/src/address-manager/ip-mappings.ts +191 -0
  54. package/src/address-manager/observed-addresses.ts +94 -0
  55. package/src/address-manager/transport-addresses.ts +116 -0
  56. package/src/config/connection-gater.browser.ts +18 -4
  57. package/src/connection-manager/connection-pruner.ts +6 -4
  58. package/src/connection-manager/dial-queue.ts +12 -19
  59. package/src/connection-manager/index.ts +14 -8
  60. package/src/connection-manager/utils.ts +35 -2
  61. package/src/index.ts +1 -1
  62. package/src/libp2p.ts +1 -1
  63. package/src/version.ts +2 -2
  64. package/LICENSE +0 -4
  65. package/dist/src/address-manager.d.ts.map +0 -1
  66. package/dist/src/address-manager.js +0 -214
  67. package/dist/src/address-manager.js.map +0 -1
  68. package/dist/typedoc-urls.json +0 -19
  69. package/src/address-manager.ts +0 -319
@@ -0,0 +1,191 @@
1
+ import { isIPv4 } from '@chainsafe/is-ip'
2
+ import { multiaddr, protocols } from '@multiformats/multiaddr'
3
+ import type { AddressManagerComponents, AddressManagerInit } from './index.js'
4
+ import type { Logger } from '@libp2p/interface'
5
+ import type { NodeAddress } from '@libp2p/interface-internal'
6
+ import type { Multiaddr } from '@multiformats/multiaddr'
7
+
8
+ export const defaultValues = {
9
+ maxObservedAddresses: 10
10
+ }
11
+
12
+ interface PublicAddressMapping {
13
+ internalIp: string
14
+ internalPort: number
15
+ externalIp: string
16
+ externalPort: number
17
+ externalFamily: 4 | 6
18
+ protocol: 'tcp' | 'udp'
19
+ verified: boolean
20
+ expires: number
21
+ lastVerified?: number
22
+ }
23
+
24
+ const CODEC_IP4 = 0x04
25
+ const CODEC_IP6 = 0x29
26
+ const CODEC_TCP = 0x06
27
+ const CODEC_UDP = 0x0111
28
+
29
+ export class IPMappings {
30
+ private readonly log: Logger
31
+ private readonly mappings: Map<string, PublicAddressMapping[]>
32
+
33
+ constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
34
+ this.log = components.logger.forComponent('libp2p:address-manager:ip-mappings')
35
+ this.mappings = new Map()
36
+ }
37
+
38
+ has (ma: Multiaddr): boolean {
39
+ const tuples = ma.stringTuples()
40
+
41
+ for (const mappings of this.mappings.values()) {
42
+ for (const mapping of mappings) {
43
+ if (mapping.externalIp === tuples[0][1]) {
44
+ return true
45
+ }
46
+ }
47
+ }
48
+
49
+ return false
50
+ }
51
+
52
+ add (internalIp: string, internalPort: number, externalIp: string, externalPort: number = internalPort, protocol: 'tcp' | 'udp' = 'tcp'): void {
53
+ const key = `${internalIp}-${internalPort}-${protocol}`
54
+ const mappings = this.mappings.get(key) ?? []
55
+ const mapping: PublicAddressMapping = {
56
+ internalIp,
57
+ internalPort,
58
+ externalIp,
59
+ externalPort,
60
+ externalFamily: isIPv4(externalIp) ? 4 : 6,
61
+ protocol,
62
+ verified: false,
63
+ expires: 0
64
+ }
65
+ mappings.push(mapping)
66
+
67
+ this.mappings.set(key, mappings)
68
+ }
69
+
70
+ remove (ma: Multiaddr): boolean {
71
+ const tuples = ma.stringTuples()
72
+ const host = tuples[0][1] ?? ''
73
+ const protocol = tuples[1][0] === CODEC_TCP ? 'tcp' : 'udp'
74
+ const port = parseInt(tuples[1][1] ?? '0')
75
+ let wasConfident = false
76
+
77
+ for (const [key, mappings] of this.mappings.entries()) {
78
+ for (let i = 0; i < mappings.length; i++) {
79
+ const mapping = mappings[i]
80
+
81
+ if (mapping.externalIp === host && mapping.externalPort === port && mapping.protocol === protocol) {
82
+ this.log('removing %s:%s to %s:%s %s IP mapping', mapping.externalIp, mapping.externalPort, host, port, protocol)
83
+
84
+ wasConfident = wasConfident || mapping.verified
85
+ mappings.splice(i, 1)
86
+ i--
87
+ }
88
+ }
89
+
90
+ if (mappings.length === 0) {
91
+ this.mappings.delete(key)
92
+ }
93
+ }
94
+
95
+ return wasConfident
96
+ }
97
+
98
+ getAll (addresses: NodeAddress[]): NodeAddress[] {
99
+ const ipMappedAddresses: NodeAddress[] = []
100
+
101
+ for (const { multiaddr: ma } of addresses) {
102
+ const tuples = ma.stringTuples()
103
+ let tuple: string | undefined
104
+
105
+ // see if the internal host/port/protocol tuple has been mapped externally
106
+ if ((tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) && tuples[1][0] === CODEC_TCP) {
107
+ tuple = `${tuples[0][1]}-${tuples[1][1]}-tcp`
108
+ } else if ((tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) && tuples[1][0] === CODEC_UDP) {
109
+ tuple = `${tuples[0][1]}-${tuples[1][1]}-udp`
110
+ }
111
+
112
+ if (tuple == null) {
113
+ continue
114
+ }
115
+
116
+ const mappings = this.mappings.get(tuple)
117
+
118
+ if (mappings == null) {
119
+ continue
120
+ }
121
+
122
+ for (const mapping of mappings) {
123
+ tuples[0][0] = mapping.externalFamily === 4 ? CODEC_IP4 : CODEC_IP6
124
+ tuples[0][1] = mapping.externalIp
125
+ tuples[1][1] = `${mapping.externalPort}`
126
+
127
+ ipMappedAddresses.push({
128
+ multiaddr: multiaddr(`/${
129
+ tuples.map(tuple => {
130
+ return [
131
+ protocols(tuple[0]).name,
132
+ tuple[1]
133
+ ].join('/')
134
+ }).join('/')
135
+ }`),
136
+ verified: mapping.verified,
137
+ type: 'ip-mapping',
138
+ expires: mapping.expires,
139
+ lastVerified: mapping.lastVerified
140
+ })
141
+ }
142
+ }
143
+
144
+ return ipMappedAddresses
145
+ }
146
+
147
+ confirm (ma: Multiaddr, ttl: number): boolean {
148
+ const tuples = ma.stringTuples()
149
+ const host = tuples[0][1]
150
+ let startingConfidence = false
151
+
152
+ for (const mappings of this.mappings.values()) {
153
+ for (const mapping of mappings) {
154
+ // eslint-disable-next-line max-depth
155
+ if (mapping.externalIp === host) {
156
+ this.log('marking %s to %s IP mapping as verified', mapping.internalIp, mapping.externalIp)
157
+ startingConfidence = mapping.verified
158
+ mapping.verified = true
159
+ mapping.expires = Date.now() + ttl
160
+ mapping.lastVerified = Date.now()
161
+ }
162
+ }
163
+ }
164
+
165
+ return startingConfidence
166
+ }
167
+
168
+ unconfirm (ma: Multiaddr, ttl: number): boolean {
169
+ const tuples = ma.stringTuples()
170
+ const host = tuples[0][1] ?? ''
171
+ const protocol = tuples[1][0] === CODEC_TCP ? 'tcp' : 'udp'
172
+ const port = parseInt(tuples[1][1] ?? '0')
173
+ let wasConfident = false
174
+
175
+ for (const mappings of this.mappings.values()) {
176
+ for (let i = 0; i < mappings.length; i++) {
177
+ const mapping = mappings[i]
178
+
179
+ if (mapping.externalIp === host && mapping.externalPort === port && mapping.protocol === protocol) {
180
+ this.log('removing verification of %s:%s to %s:%s %s IP mapping', mapping.externalIp, mapping.externalPort, host, port, protocol)
181
+
182
+ wasConfident = wasConfident || mapping.verified
183
+ mapping.verified = false
184
+ mapping.expires = Date.now() + ttl
185
+ }
186
+ }
187
+ }
188
+
189
+ return wasConfident
190
+ }
191
+ }
@@ -0,0 +1,94 @@
1
+ import { isLinkLocal } from '@libp2p/utils/multiaddr/is-link-local'
2
+ import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
3
+ import { multiaddr } from '@multiformats/multiaddr'
4
+ import type { AddressManagerComponents, AddressManagerInit } from './index.js'
5
+ import type { Logger } from '@libp2p/interface'
6
+ import type { NodeAddress } from '@libp2p/interface-internal'
7
+ import type { Multiaddr } from '@multiformats/multiaddr'
8
+
9
+ export const defaultValues = {
10
+ maxObservedAddresses: 10
11
+ }
12
+
13
+ interface ObservedAddressMetadata {
14
+ verified: boolean
15
+ expires: number
16
+ lastVerified?: number
17
+ }
18
+
19
+ export class ObservedAddresses {
20
+ private readonly log: Logger
21
+ private readonly addresses: Map<string, ObservedAddressMetadata>
22
+ private readonly maxObservedAddresses: number
23
+
24
+ constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
25
+ this.log = components.logger.forComponent('libp2p:address-manager:observed-addresses')
26
+ this.addresses = new Map()
27
+ this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses
28
+ }
29
+
30
+ has (ma: Multiaddr): boolean {
31
+ return this.addresses.has(ma.toString())
32
+ }
33
+
34
+ removePrefixed (prefix: string): void {
35
+ for (const key of this.addresses.keys()) {
36
+ if (key.toString().startsWith(prefix)) {
37
+ this.addresses.delete(key)
38
+ }
39
+ }
40
+ }
41
+
42
+ add (ma: Multiaddr): void {
43
+ if (this.addresses.size === this.maxObservedAddresses) {
44
+ return
45
+ }
46
+
47
+ if (isPrivate(ma) || isLinkLocal(ma)) {
48
+ return
49
+ }
50
+
51
+ this.log('adding observed address %a', ma)
52
+ this.addresses.set(ma.toString(), {
53
+ verified: false,
54
+ expires: 0
55
+ })
56
+ }
57
+
58
+ getAll (): NodeAddress[] {
59
+ return Array.from(this.addresses)
60
+ .map(([ma, metadata]) => ({
61
+ multiaddr: multiaddr(ma),
62
+ verified: metadata.verified,
63
+ type: 'observed',
64
+ expires: metadata.expires,
65
+ lastVerified: metadata.lastVerified
66
+ }))
67
+ }
68
+
69
+ remove (ma: Multiaddr): boolean {
70
+ const startingConfidence = this.addresses.get(ma.toString())?.verified ?? false
71
+
72
+ this.log('removing observed address %a', ma)
73
+ this.addresses.delete(ma.toString())
74
+
75
+ return startingConfidence
76
+ }
77
+
78
+ confirm (ma: Multiaddr, ttl: number): boolean {
79
+ const addrString = ma.toString()
80
+ const metadata = this.addresses.get(addrString) ?? {
81
+ verified: false,
82
+ expires: Date.now() + ttl,
83
+ lastVerified: Date.now()
84
+ }
85
+ const startingConfidence = metadata.verified
86
+ metadata.verified = true
87
+ metadata.lastVerified = Date.now()
88
+
89
+ this.log('marking observed address %a as verified', addrString)
90
+ this.addresses.set(addrString, metadata)
91
+
92
+ return startingConfidence
93
+ }
94
+ }
@@ -0,0 +1,116 @@
1
+ import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
2
+ import type { AddressManagerComponents, AddressManagerInit } from './index.js'
3
+ import type { Logger } from '@libp2p/interface'
4
+ import type { NodeAddress } from '@libp2p/interface-internal'
5
+ import type { Multiaddr } from '@multiformats/multiaddr'
6
+
7
+ export const defaultValues = {
8
+ maxObservedAddresses: 10
9
+ }
10
+
11
+ interface TransportAddressMetadata {
12
+ verified: boolean
13
+ expires: number
14
+ lastVerified?: number
15
+ }
16
+
17
+ export class TransportAddresses {
18
+ private readonly log: Logger
19
+ private readonly addresses: Map<string, TransportAddressMetadata>
20
+ private readonly maxObservedAddresses: number
21
+
22
+ constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) {
23
+ this.log = components.logger.forComponent('libp2p:address-manager:observed-addresses')
24
+ this.addresses = new Map()
25
+ this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses
26
+ }
27
+
28
+ get (multiaddr: Multiaddr, ttl: number): NodeAddress {
29
+ if (isPrivate(multiaddr)) {
30
+ return {
31
+ multiaddr,
32
+ verified: true,
33
+ type: 'transport',
34
+ expires: Date.now() + ttl,
35
+ lastVerified: Date.now()
36
+ }
37
+ }
38
+
39
+ const key = this.toKey(multiaddr)
40
+ let metadata = this.addresses.get(key)
41
+
42
+ if (metadata == null) {
43
+ metadata = {
44
+ verified: false,
45
+ expires: 0
46
+ }
47
+
48
+ this.addresses.set(key, metadata)
49
+ }
50
+
51
+ return {
52
+ multiaddr,
53
+ verified: metadata.verified,
54
+ type: 'transport',
55
+ expires: metadata.expires,
56
+ lastVerified: metadata.lastVerified
57
+ }
58
+ }
59
+
60
+ has (ma: Multiaddr): boolean {
61
+ const key = this.toKey(ma)
62
+ return this.addresses.has(key)
63
+ }
64
+
65
+ remove (ma: Multiaddr): boolean {
66
+ const key = this.toKey(ma)
67
+ const startingConfidence = this.addresses.get(key)?.verified ?? false
68
+
69
+ this.log('removing observed address %a', ma)
70
+ this.addresses.delete(key)
71
+
72
+ return startingConfidence
73
+ }
74
+
75
+ confirm (ma: Multiaddr, ttl: number): boolean {
76
+ const key = this.toKey(ma)
77
+ const metadata = this.addresses.get(key) ?? {
78
+ verified: false,
79
+ expires: 0,
80
+ lastVerified: 0
81
+ }
82
+
83
+ const startingConfidence = metadata.verified
84
+
85
+ metadata.verified = true
86
+ metadata.expires = Date.now() + ttl
87
+ metadata.lastVerified = Date.now()
88
+
89
+ this.addresses.set(key, metadata)
90
+
91
+ return startingConfidence
92
+ }
93
+
94
+ unconfirm (ma: Multiaddr, ttl: number): boolean {
95
+ const key = this.toKey(ma)
96
+ const metadata = this.addresses.get(key) ?? {
97
+ verified: false,
98
+ expires: 0
99
+ }
100
+
101
+ const startingConfidence = metadata.verified
102
+
103
+ metadata.verified = false
104
+ metadata.expires = Date.now() + ttl
105
+
106
+ this.addresses.set(key, metadata)
107
+
108
+ return startingConfidence
109
+ }
110
+
111
+ private toKey (ma: Multiaddr): string {
112
+ const options = ma.toOptions()
113
+
114
+ return `${options.host}-${options.port}-${options.transport}`
115
+ }
116
+ }
@@ -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,6 +1,8 @@
1
1
  import { PeerMap } from '@libp2p/peer-collections'
2
2
  import { safelyCloseConnectionIfUnused } from '@libp2p/utils/close'
3
3
  import { MAX_CONNECTIONS } from './constants.js'
4
+ import { multiaddrToIpNet } from './utils.js'
5
+ import type { IpNet } from '@chainsafe/netmask'
4
6
  import type { Libp2pEvents, Logger, ComponentLogger, TypedEventTarget, PeerStore, Connection } from '@libp2p/interface'
5
7
  import type { ConnectionManager } from '@libp2p/interface-internal'
6
8
  import type { Multiaddr } from '@multiformats/multiaddr'
@@ -29,13 +31,13 @@ export class ConnectionPruner {
29
31
  private readonly maxConnections: number
30
32
  private readonly connectionManager: ConnectionManager
31
33
  private readonly peerStore: PeerStore
32
- private readonly allow: Multiaddr[]
34
+ private readonly allow: IpNet[]
33
35
  private readonly events: TypedEventTarget<Libp2pEvents>
34
36
  private readonly log: Logger
35
37
 
36
38
  constructor (components: ConnectionPrunerComponents, init: ConnectionPrunerInit = {}) {
37
39
  this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections
38
- this.allow = init.allow ?? defaultOptions.allow
40
+ this.allow = (init.allow ?? []).map(ma => multiaddrToIpNet(ma))
39
41
  this.connectionManager = components.connectionManager
40
42
  this.peerStore = components.peerStore
41
43
  this.events = components.events
@@ -107,8 +109,8 @@ export class ConnectionPruner {
107
109
  for (const connection of sortedConnections) {
108
110
  this.log('too many connections open - closing a connection to %p', connection.remotePeer)
109
111
  // check allow list
110
- const connectionInAllowList = this.allow.some((ma) => {
111
- return connection.remoteAddr.toString().startsWith(ma.toString())
112
+ const connectionInAllowList = this.allow.some((ipNet) => {
113
+ return ipNet.contains(connection.remoteAddr.nodeAddress().address)
112
114
  })
113
115
 
114
116
  // Connections in the allow list should be excluded from pruning
@@ -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 => ({
@@ -9,6 +9,8 @@ import { ConnectionPruner } from './connection-pruner.js'
9
9
  import { DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_CONNECTIONS, MAX_DIAL_QUEUE_LENGTH, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL } from './constants.js'
10
10
  import { DialQueue } from './dial-queue.js'
11
11
  import { ReconnectQueue } from './reconnect-queue.js'
12
+ import { multiaddrToIpNet } from './utils.js'
13
+ import type { IpNet } from '@chainsafe/netmask'
12
14
  import type { PendingDial, AddressSorter, Libp2pEvents, AbortOptions, ComponentLogger, Logger, Connection, MultiaddrConnection, ConnectionGater, TypedEventTarget, Metrics, PeerId, PeerStore, Startable, PendingDialStatus, PeerRouting, IsDialableOptions } from '@libp2p/interface'
13
15
  import type { ConnectionManager, OpenConnectionOptions, TransportManager } from '@libp2p/interface-internal'
14
16
  import type { JobStatus } from '@libp2p/utils/queue'
@@ -176,8 +178,8 @@ export interface DefaultConnectionManagerComponents {
176
178
  export class DefaultConnectionManager implements ConnectionManager, Startable {
177
179
  private started: boolean
178
180
  private readonly connections: PeerMap<Connection[]>
179
- private readonly allow: Multiaddr[]
180
- private readonly deny: Multiaddr[]
181
+ private readonly allow: IpNet[]
182
+ private readonly deny: IpNet[]
181
183
  private readonly maxIncomingPendingConnections: number
182
184
  private incomingPendingConnections: number
183
185
  private outboundPendingConnections: number
@@ -216,8 +218,8 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
216
218
  this.onDisconnect = this.onDisconnect.bind(this)
217
219
 
218
220
  // allow/deny lists
219
- this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
220
- this.deny = (init.deny ?? []).map(ma => multiaddr(ma))
221
+ this.allow = (init.allow ?? []).map(str => multiaddrToIpNet(str))
222
+ this.deny = (init.deny ?? []).map(str => multiaddrToIpNet(str))
221
223
 
222
224
  this.incomingPendingConnections = 0
223
225
  this.maxIncomingPendingConnections = init.maxIncomingPendingConnections ?? defaultOptions.maxIncomingPendingConnections
@@ -237,7 +239,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
237
239
  logger: components.logger
238
240
  }, {
239
241
  maxConnections: this.maxConnections,
240
- allow: this.allow
242
+ allow: init.allow?.map(a => multiaddr(a))
241
243
  })
242
244
 
243
245
  this.dialQueue = new DialQueue(components, {
@@ -395,6 +397,10 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
395
397
  this.log('stopped')
396
398
  }
397
399
 
400
+ getMaxConnections (): number {
401
+ return this.maxConnections
402
+ }
403
+
398
404
  onConnect (evt: CustomEvent<Connection>): void {
399
405
  void this._onConnect(evt).catch(err => {
400
406
  this.log.error(err)
@@ -571,7 +577,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
571
577
  async acceptIncomingConnection (maConn: MultiaddrConnection): Promise<boolean> {
572
578
  // check deny list
573
579
  const denyConnection = this.deny.some(ma => {
574
- return maConn.remoteAddr.toString().startsWith(ma.toString())
580
+ return ma.contains(maConn.remoteAddr.nodeAddress().address)
575
581
  })
576
582
 
577
583
  if (denyConnection) {
@@ -580,8 +586,8 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
580
586
  }
581
587
 
582
588
  // check allow list
583
- const allowConnection = this.allow.some(ma => {
584
- return maConn.remoteAddr.toString().startsWith(ma.toString())
589
+ const allowConnection = this.allow.some(ipNet => {
590
+ return ipNet.contains(maConn.remoteAddr.nodeAddress().address)
585
591
  })
586
592
 
587
593
  if (allowConnection) {
@@ -1,6 +1,7 @@
1
- import { resolvers } from '@multiformats/multiaddr'
1
+ import { multiaddr, resolvers, type Multiaddr, type ResolveOptions } from '@multiformats/multiaddr'
2
+ import { convertToIpNet } from '@multiformats/multiaddr/convert'
3
+ import type { IpNet } from '@chainsafe/netmask'
2
4
  import type { LoggerOptions } from '@libp2p/interface'
3
- import type { Multiaddr, ResolveOptions } from '@multiformats/multiaddr'
4
5
 
5
6
  /**
6
7
  * Recursively resolve DNSADDR multiaddrs
@@ -28,3 +29,35 @@ export async function resolveMultiaddrs (ma: Multiaddr, options: ResolveOptions
28
29
 
29
30
  return output
30
31
  }
32
+
33
+ /**
34
+ * Converts a multiaddr string or object to an IpNet object.
35
+ * If the multiaddr doesn't include /ipcidr, it will encapsulate with the appropriate CIDR:
36
+ * - /ipcidr/32 for IPv4
37
+ * - /ipcidr/128 for IPv6
38
+ *
39
+ * @param {string | Multiaddr} ma - The multiaddr string or object to convert.
40
+ * @returns {IpNet} The converted IpNet object.
41
+ * @throws {Error} Throws an error if the multiaddr is not valid.
42
+ */
43
+ export function multiaddrToIpNet (ma: string | Multiaddr): IpNet {
44
+ try {
45
+ let parsedMa: Multiaddr
46
+ if (typeof ma === 'string') {
47
+ parsedMa = multiaddr(ma)
48
+ } else {
49
+ parsedMa = ma
50
+ }
51
+
52
+ // Check if /ipcidr is already present
53
+ if (!parsedMa.protoNames().includes('ipcidr')) {
54
+ const isIPv6 = parsedMa.protoNames().includes('ip6')
55
+ const cidr = isIPv6 ? '/ipcidr/128' : '/ipcidr/32'
56
+ parsedMa = parsedMa.encapsulate(cidr)
57
+ }
58
+
59
+ return convertToIpNet(parsedMa)
60
+ } catch (error) {
61
+ throw new Error(`Can't convert to IpNet, Invalid multiaddr format: ${ma}`)
62
+ }
63
+ }
package/src/index.ts CHANGED
@@ -18,7 +18,7 @@ import { generateKeyPair } from '@libp2p/crypto/keys'
18
18
  import { peerIdFromPrivateKey } from '@libp2p/peer-id'
19
19
  import { validateConfig } from './config.js'
20
20
  import { Libp2p as Libp2pClass } from './libp2p.js'
21
- import type { AddressManagerInit, AddressFilter } from './address-manager.js'
21
+ import type { AddressManagerInit, AddressFilter } from './address-manager/index.js'
22
22
  import type { Components } from './components.js'
23
23
  import type { ConnectionManagerInit } from './connection-manager/index.js'
24
24
  import type { ConnectionMonitorInit } from './connection-monitor.js'
package/src/libp2p.ts CHANGED
@@ -8,7 +8,7 @@ import { isMultiaddr, type Multiaddr } from '@multiformats/multiaddr'
8
8
  import { MemoryDatastore } from 'datastore-core/memory'
9
9
  import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
10
10
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
11
- import { AddressManager } from './address-manager.js'
11
+ import { AddressManager } from './address-manager/index.js'
12
12
  import { checkServiceDependencies, defaultComponents } from './components.js'
13
13
  import { connectionGater } from './config/connection-gater.js'
14
14
  import { DefaultConnectionManager } from './connection-manager/index.js'
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '2.3.1'
2
- export const name = 'libp2p'
1
+ export const version = '2.4.0-127abe24b'
2
+ export const name = 'js-libp2p'