libp2p 2.3.1 → 2.4.0-5c4a79e5a
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/README.md +9 -25
- package/dist/index.min.js +18 -15
- package/dist/src/address-manager/dns-mappings.d.ts +20 -0
- package/dist/src/address-manager/dns-mappings.d.ts.map +1 -0
- package/dist/src/address-manager/dns-mappings.js +139 -0
- package/dist/src/address-manager/dns-mappings.js.map +1 -0
- package/dist/src/{address-manager.d.ts → address-manager/index.d.ts} +54 -10
- package/dist/src/address-manager/index.d.ts.map +1 -0
- package/dist/src/address-manager/index.js +264 -0
- package/dist/src/address-manager/index.js.map +1 -0
- package/dist/src/address-manager/ip-mappings.d.ts +18 -0
- package/dist/src/address-manager/ip-mappings.d.ts.map +1 -0
- package/dist/src/address-manager/ip-mappings.js +143 -0
- package/dist/src/address-manager/ip-mappings.js.map +1 -0
- package/dist/src/address-manager/observed-addresses.d.ts +19 -0
- package/dist/src/address-manager/observed-addresses.d.ts.map +1 -0
- package/dist/src/address-manager/observed-addresses.js +70 -0
- package/dist/src/address-manager/observed-addresses.js.map +1 -0
- package/dist/src/address-manager/transport-addresses.d.ts +19 -0
- package/dist/src/address-manager/transport-addresses.d.ts.map +1 -0
- package/dist/src/address-manager/transport-addresses.js +83 -0
- package/dist/src/address-manager/transport-addresses.js.map +1 -0
- package/dist/src/config/connection-gater.browser.d.ts +7 -3
- package/dist/src/config/connection-gater.browser.d.ts.map +1 -1
- package/dist/src/config/connection-gater.browser.js +16 -4
- package/dist/src/config/connection-gater.browser.js.map +1 -1
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
- package/dist/src/connection-manager/connection-pruner.js +4 -3
- package/dist/src/connection-manager/connection-pruner.js.map +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts +3 -3
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
- package/dist/src/connection-manager/dial-queue.js +6 -13
- package/dist/src/connection-manager/dial-queue.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +1 -0
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +10 -6
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/utils.d.ts +13 -1
- package/dist/src/connection-manager/utils.d.ts.map +1 -1
- package/dist/src/connection-manager/utils.js +33 -1
- package/dist/src/connection-manager/utils.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/libp2p.js +1 -1
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js +2 -2
- package/dist/src/version.js.map +1 -1
- package/package.json +27 -25
- package/src/address-manager/dns-mappings.ts +182 -0
- package/src/address-manager/index.ts +413 -0
- package/src/address-manager/ip-mappings.ts +191 -0
- package/src/address-manager/observed-addresses.ts +94 -0
- package/src/address-manager/transport-addresses.ts +116 -0
- package/src/config/connection-gater.browser.ts +18 -4
- package/src/connection-manager/connection-pruner.ts +6 -4
- package/src/connection-manager/dial-queue.ts +12 -19
- package/src/connection-manager/index.ts +14 -8
- package/src/connection-manager/utils.ts +35 -2
- package/src/index.ts +1 -1
- package/src/libp2p.ts +1 -1
- package/src/version.ts +2 -2
- package/LICENSE +0 -4
- package/dist/src/address-manager.d.ts.map +0 -1
- package/dist/src/address-manager.js +0 -214
- package/dist/src/address-manager.js.map +0 -1
- package/dist/typedoc-urls.json +0 -19
- 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
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
|
|
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:
|
|
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 ??
|
|
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((
|
|
111
|
-
return connection.remoteAddr.
|
|
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
|
|
5
|
-
import {
|
|
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 {
|
|
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 =
|
|
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:
|
|
180
|
-
private readonly deny:
|
|
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(
|
|
220
|
-
this.deny = (init.deny ?? []).map(
|
|
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:
|
|
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.
|
|
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(
|
|
584
|
-
return maConn.remoteAddr.
|
|
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.
|
|
2
|
-
export const name = 'libp2p'
|
|
1
|
+
export const version = '2.4.0-5c4a79e5a'
|
|
2
|
+
export const name = 'js-libp2p'
|