@libp2p/autonat-v2 1.0.1 → 2.0.0-049bfa0fa

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/src/client.ts CHANGED
@@ -1,23 +1,16 @@
1
- import { ProtocolError, serviceCapabilities, serviceDependencies } from '@libp2p/interface'
1
+ import { InvalidParametersError, ProtocolError, serviceCapabilities, serviceDependencies } from '@libp2p/interface'
2
2
  import { peerSet } from '@libp2p/peer-collections'
3
- import { createScalableCuckooFilter } from '@libp2p/utils/filters'
4
- import { isGlobalUnicast } from '@libp2p/utils/multiaddr/is-global-unicast'
5
- import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
6
- import { PeerQueue } from '@libp2p/utils/peer-queue'
7
- import { repeatingTask } from '@libp2p/utils/repeating-task'
8
- import { trackedMap } from '@libp2p/utils/tracked-map'
3
+ import { createScalableCuckooFilter, isGlobalUnicast, isPrivate, PeerQueue, repeatingTask, trackedMap, pbStream, getNetConfig } from '@libp2p/utils'
9
4
  import { anySignal } from 'any-signal'
10
- import { pbStream } from 'it-protobuf-stream'
11
5
  import { setMaxListeners } from 'main-event'
12
6
  import { DEFAULT_CONNECTION_THRESHOLD, DIAL_DATA_CHUNK_SIZE, MAX_DIAL_DATA_BYTES, MAX_INBOUND_STREAMS, MAX_MESSAGE_SIZE, MAX_OUTBOUND_STREAMS, TIMEOUT } from './constants.ts'
13
7
  import { DialBack, DialBackResponse, DialResponse, DialStatus, Message } from './pb/index.ts'
14
8
  import { randomNumber } from './utils.ts'
15
9
  import type { AutoNATv2Components, AutoNATv2ServiceInit } from './index.ts'
16
- import type { Logger, Connection, Startable, AbortOptions, IncomingStreamData } from '@libp2p/interface'
10
+ import type { Logger, Connection, Startable, AbortOptions, Stream } from '@libp2p/interface'
17
11
  import type { AddressType } from '@libp2p/interface-internal'
18
12
  import type { PeerSet } from '@libp2p/peer-collections'
19
- import type { Filter } from '@libp2p/utils/filters'
20
- import type { RepeatingTask } from '@libp2p/utils/repeating-task'
13
+ import type { Filter, RepeatingTask } from '@libp2p/utils'
21
14
  import type { Multiaddr } from '@multiformats/multiaddr'
22
15
 
23
16
  // if more than 3 peers manage to dial us on what we believe to be our external
@@ -154,8 +147,8 @@ export class AutoNATv2Client implements Startable {
154
147
  }
155
148
  })
156
149
 
157
- await this.components.registrar.handle(this.dialBackProtocol, (data) => {
158
- void this.handleDialBackStream(data)
150
+ await this.components.registrar.handle(this.dialBackProtocol, (stream, connection) => {
151
+ void this.handleDialBackStream(stream, connection)
159
152
  .catch(err => {
160
153
  this.log.error('error handling incoming autonat stream - %e', err)
161
154
  })
@@ -239,11 +232,11 @@ export class AutoNATv2Client implements Startable {
239
232
  /**
240
233
  * Handle an incoming AutoNAT request
241
234
  */
242
- async handleDialBackStream (data: IncomingStreamData): Promise<void> {
235
+ async handleDialBackStream (stream: Stream, connection: Connection): Promise<void> {
243
236
  const signal = AbortSignal.timeout(this.timeout)
244
237
  setMaxListeners(Infinity, signal)
245
238
 
246
- const messages = pbStream(data.stream, {
239
+ const messages = pbStream(stream, {
247
240
  maxDataLength: this.maxMessageSize
248
241
  })
249
242
 
@@ -264,12 +257,12 @@ export class AutoNATv2Client implements Startable {
264
257
  status: DialBackResponse.DialBackStatus.OK
265
258
  }, DialBackResponse)
266
259
 
267
- await data.stream.close({
260
+ await stream.close({
268
261
  signal
269
262
  })
270
263
  } catch (err: any) {
271
264
  this.log.error('error handling incoming dial back stream - %e', err)
272
- data.stream.abort(err)
265
+ stream.abort(err)
273
266
  }
274
267
  }
275
268
 
@@ -295,9 +288,9 @@ export class AutoNATv2Client implements Startable {
295
288
  return false
296
289
  }
297
290
 
298
- const options = addr.multiaddr.toOptions()
291
+ const options = getNetConfig(addr.multiaddr)
299
292
 
300
- if (options.family === 6) {
293
+ if (options.type === 'ip6') {
301
294
  // do not send IPv6 addresses to peers without IPv6 addresses
302
295
  if (!supportsIPv6) {
303
296
  return false
@@ -409,7 +402,7 @@ export class AutoNATv2Client implements Startable {
409
402
  // if the remote peer has IPv6 addresses, we can probably send them an IPv6
410
403
  // address to verify, otherwise only send them IPv4 addresses
411
404
  const supportsIPv6 = peer.addresses.some(({ multiaddr }) => {
412
- return multiaddr.toOptions().family === 6
405
+ return getNetConfig(multiaddr).type === 'ip6'
413
406
  })
414
407
 
415
408
  // get multiaddrs this peer is eligible to verify
@@ -465,7 +458,7 @@ export class AutoNATv2Client implements Startable {
465
458
  return
466
459
  }
467
460
 
468
- this.log.trace('asking %p to verify multiaddrs %s', connection.remotePeer, unverifiedAddresses)
461
+ this.log.trace('asking %a to verify multiaddrs %s', connection.remoteAddr, unverifiedAddresses)
469
462
 
470
463
  const stream = await connection.newStream(this.dialRequestProtocol, options)
471
464
 
@@ -478,7 +471,7 @@ export class AutoNATv2Client implements Startable {
478
471
  }
479
472
  }, options)
480
473
 
481
- while (true) {
474
+ for (let i = 0; i < unverifiedAddresses.length; i++) {
482
475
  let response = await messages.read(options)
483
476
 
484
477
  if (response.dialDataRequest != null) {
@@ -615,14 +608,20 @@ export class AutoNATv2Client implements Startable {
615
608
 
616
609
  private getNetworkSegment (ma: Multiaddr): string {
617
610
  // make sure we use different network segments
618
- const options = ma.toOptions()
611
+ const options = getNetConfig(ma)
619
612
 
620
- if (options.family === 4) {
621
- const octets = options.host.split('.')
622
- return octets[0].padStart(3, '0')
613
+ switch (options.type) {
614
+ case 'ip4': {
615
+ const octets = options.host.split('.')
616
+ return octets[0].padStart(3, '0')
617
+ }
618
+ case 'ip6': {
619
+ const octets = options.host.split(':')
620
+ return octets[0].padStart(4, '0')
621
+ }
622
+ default: {
623
+ throw new InvalidParametersError(`Remote address ${ma} was not an IPv4 or Ipv6 address`)
624
+ }
623
625
  }
624
-
625
- const octets = options.host.split(':')
626
- return octets[0].padStart(4, '0')
627
626
  }
628
627
  }
package/src/server.ts CHANGED
@@ -1,15 +1,14 @@
1
1
  import { ProtocolError } from '@libp2p/interface'
2
- import { isPrivateIp } from '@libp2p/utils/private-ip'
2
+ import { isPrivateIp, pbStream } from '@libp2p/utils'
3
3
  import { CODE_IP4, CODE_IP6, multiaddr } from '@multiformats/multiaddr'
4
- import { pbStream } from 'it-protobuf-stream'
5
4
  import { setMaxListeners } from 'main-event'
6
5
  import { MAX_INBOUND_STREAMS, MAX_MESSAGE_SIZE, MAX_OUTBOUND_STREAMS, TIMEOUT } from './constants.ts'
7
6
  import { DialBack, DialBackResponse, DialResponse, DialStatus, Message } from './pb/index.ts'
8
7
  import { randomNumber } from './utils.ts'
9
8
  import type { AutoNATv2Components, AutoNATv2ServiceInit } from './index.ts'
10
- import type { Logger, Connection, Startable, AbortOptions, IncomingStreamData, Stream } from '@libp2p/interface'
9
+ import type { Logger, Connection, Startable, AbortOptions, Stream } from '@libp2p/interface'
10
+ import type { ProtobufMessageStream } from '@libp2p/utils'
11
11
  import type { Multiaddr } from '@multiformats/multiaddr'
12
- import type { MessageStream } from 'it-protobuf-stream'
13
12
 
14
13
  export interface AutoNATv2ServerInit extends AutoNATv2ServiceInit {
15
14
  dialRequestProtocol: string
@@ -37,6 +36,8 @@ export class AutoNATv2Server implements Startable {
37
36
  this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS
38
37
  this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS
39
38
  this.maxMessageSize = init.maxMessageSize ?? MAX_MESSAGE_SIZE
39
+
40
+ this.handleDialRequestStream = this.handleDialRequestStream.bind(this)
40
41
  }
41
42
 
42
43
  async start (): Promise<void> {
@@ -45,12 +46,7 @@ export class AutoNATv2Server implements Startable {
45
46
  }
46
47
 
47
48
  // AutoNat server
48
- await this.components.registrar.handle(this.dialRequestProtocol, (data) => {
49
- void this.handleDialRequestStream(data)
50
- .catch(err => {
51
- this.log.error('error handling incoming autonat stream - %e', err)
52
- })
53
- }, {
49
+ await this.components.registrar.handle(this.dialRequestProtocol, this.handleDialRequestStream, {
54
50
  maxInboundStreams: this.maxInboundStreams,
55
51
  maxOutboundStreams: this.maxOutboundStreams
56
52
  })
@@ -67,100 +63,95 @@ export class AutoNATv2Server implements Startable {
67
63
  /**
68
64
  * Handle an incoming AutoNAT request
69
65
  */
70
- async handleDialRequestStream (data: IncomingStreamData): Promise<void> {
66
+ async handleDialRequestStream (stream: Stream, connection: Connection): Promise<void> {
71
67
  const signal = AbortSignal.timeout(this.timeout)
72
68
  setMaxListeners(Infinity, signal)
73
69
 
74
- const messages = pbStream(data.stream, {
70
+ const messages = pbStream(stream, {
75
71
  maxDataLength: this.maxMessageSize
76
72
  }).pb(Message)
77
73
 
78
- try {
79
- const connectionIp = getIpAddress(data.connection.remoteAddr)
74
+ const connectionIp = getIpAddress(connection.remoteAddr)
80
75
 
81
- if (connectionIp == null) {
82
- throw new ProtocolError(`Could not find IP address in connection address "${data.connection.remoteAddr}"`)
83
- }
76
+ if (connectionIp == null) {
77
+ throw new ProtocolError(`Could not find IP address in connection address "${connection.remoteAddr}"`)
78
+ }
84
79
 
85
- const { dialRequest } = await messages.read({
86
- signal
87
- })
80
+ const { dialRequest } = await messages.read({
81
+ signal
82
+ })
88
83
 
89
- if (dialRequest == null) {
90
- throw new ProtocolError('Did not receive DialRequest message on incoming dial request stream')
91
- }
84
+ if (dialRequest == null) {
85
+ throw new ProtocolError('Did not receive DialRequest message on incoming dial request stream')
86
+ }
92
87
 
93
- if (dialRequest.addrs.length === 0) {
94
- throw new ProtocolError('Did not receive any addresses to dial')
95
- }
88
+ if (dialRequest.addrs.length === 0) {
89
+ throw new ProtocolError('Did not receive any addresses to dial')
90
+ }
96
91
 
97
- for (let i = 0; i < dialRequest.addrs.length; i++) {
98
- try {
99
- const ma = multiaddr(dialRequest.addrs[i])
100
- const isDialable = await this.components.connectionManager.isDialable(ma, {
92
+ for (let i = 0; i < dialRequest.addrs.length; i++) {
93
+ try {
94
+ const ma = multiaddr(dialRequest.addrs[i])
95
+ const isDialable = await this.components.connectionManager.isDialable(ma, {
96
+ signal
97
+ })
98
+
99
+ if (!isDialable) {
100
+ await messages.write({
101
+ dialResponse: {
102
+ addrIdx: i,
103
+ status: DialResponse.ResponseStatus.E_DIAL_REFUSED,
104
+ dialStatus: DialStatus.UNUSED
105
+ }
106
+ }, {
101
107
  signal
102
108
  })
103
109
 
104
- if (!isDialable) {
105
- await messages.write({
106
- dialResponse: {
107
- addrIdx: i,
108
- status: DialResponse.ResponseStatus.E_DIAL_REFUSED,
109
- dialStatus: DialStatus.UNUSED
110
- }
111
- }, {
112
- signal
113
- })
114
-
115
- continue
116
- }
117
-
118
- const ip = getIpAddress(ma)
119
-
120
- if (ip == null) {
121
- throw new ProtocolError(`Could not find IP address in requested address "${ma}"`)
122
- }
110
+ continue
111
+ }
123
112
 
124
- if (isPrivateIp(ip)) {
125
- throw new ProtocolError(`Requested address had private IP "${ma}"`)
126
- }
113
+ const ip = getIpAddress(ma)
127
114
 
128
- if (ip !== connectionIp) {
129
- // amplification attack protection - request the client sends us a
130
- // random number of bytes before we'll dial the address
131
- await this.preventAmplificationAttack(messages, i, {
132
- signal
133
- })
134
- }
115
+ if (ip == null) {
116
+ throw new ProtocolError(`Could not find IP address in requested address "${ma}"`)
117
+ }
135
118
 
136
- const dialStatus = await this.dialClientBack(ma, dialRequest.nonce, {
137
- signal
138
- })
119
+ if (isPrivateIp(ip)) {
120
+ throw new ProtocolError(`Requested address had private IP "${ma}"`)
121
+ }
139
122
 
140
- await messages.write({
141
- dialResponse: {
142
- addrIdx: i,
143
- status: DialResponse.ResponseStatus.OK,
144
- dialStatus
145
- }
146
- }, {
123
+ if (ip !== connectionIp) {
124
+ // amplification attack protection - request the client sends us a
125
+ // random number of bytes before we'll dial the address
126
+ await this.preventAmplificationAttack(messages, i, {
147
127
  signal
148
128
  })
149
- } catch (err) {
150
- this.log.error('could not parse multiaddr - %e', err)
151
129
  }
152
- }
153
130
 
154
- await data.stream.close({
155
- signal
156
- })
157
- } catch (err: any) {
158
- this.log.error('error handling incoming autonat stream - %e', err)
159
- data.stream.abort(err)
131
+ const dialStatus = await this.dialClientBack(ma, dialRequest.nonce, {
132
+ signal
133
+ })
134
+
135
+ await messages.write({
136
+ dialResponse: {
137
+ addrIdx: i,
138
+ status: DialResponse.ResponseStatus.OK,
139
+ dialStatus
140
+ }
141
+ }, {
142
+ signal
143
+ })
144
+ } catch (err) {
145
+ this.log.error('error handling incoming dialback request - %e', err)
146
+ }
160
147
  }
148
+
149
+ await stream.close({
150
+ signal
151
+ })
161
152
  }
162
153
 
163
- private async preventAmplificationAttack (messages: MessageStream<Message, Stream>, index: number, options: AbortOptions): Promise<void> {
154
+ private async preventAmplificationAttack (messages: ProtobufMessageStream<Message, Stream>, index: number, options: AbortOptions): Promise<void> {
164
155
  const numBytes = randomNumber(30_000, 100_000)
165
156
 
166
157
  await messages.write({
@@ -207,7 +198,7 @@ export class AutoNATv2Server implements Startable {
207
198
  nonce
208
199
  }, DialBack, options)
209
200
 
210
- const response = await dialBackMessages.read(DialBackResponse)
201
+ const response = await dialBackMessages.read(DialBackResponse, options)
211
202
 
212
203
  if (response.status !== DialBackResponse.DialBackStatus.OK) {
213
204
  throw new ProtocolError('DialBackResponse status was not OK')
@@ -1,8 +0,0 @@
1
- {
2
- "AutoNATv2Components": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_autonat-v2.AutoNATv2Components.html",
3
- ".:AutoNATv2Components": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_autonat-v2.AutoNATv2Components.html",
4
- "AutoNATv2ServiceInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_autonat-v2.AutoNATv2ServiceInit.html",
5
- ".:AutoNATv2ServiceInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_autonat-v2.AutoNATv2ServiceInit.html",
6
- "autoNATv2": "https://libp2p.github.io/js-libp2p/functions/_libp2p_autonat-v2.autoNATv2.html",
7
- ".:autoNATv2": "https://libp2p.github.io/js-libp2p/functions/_libp2p_autonat-v2.autoNATv2.html"
8
- }