@libp2p/autonat-v2 1.0.0 → 1.0.1-a02cb0461
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +4 -4
- package/dist/src/client.d.ts +2 -2
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +9 -15
- package/dist/src/client.js.map +1 -1
- package/dist/src/server.d.ts +2 -2
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +60 -71
- package/dist/src/server.js.map +1 -1
- package/package.json +16 -17
- package/src/client.ts +11 -18
- package/src/server.ts +71 -80
- package/dist/typedoc-urls.json +0 -8
package/src/server.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { ProtocolError } from '@libp2p/interface'
|
|
2
|
-
import { isPrivateIp } from '@libp2p/utils
|
|
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,
|
|
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,
|
|
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 (
|
|
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(
|
|
70
|
+
const messages = pbStream(stream, {
|
|
75
71
|
maxDataLength: this.maxMessageSize
|
|
76
72
|
}).pb(Message)
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
const connectionIp = getIpAddress(data.connection.remoteAddr)
|
|
74
|
+
const connectionIp = getIpAddress(connection.remoteAddr)
|
|
80
75
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
if (connectionIp == null) {
|
|
77
|
+
throw new ProtocolError(`Could not find IP address in connection address "${connection.remoteAddr}"`)
|
|
78
|
+
}
|
|
84
79
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
const { dialRequest } = await messages.read({
|
|
81
|
+
signal
|
|
82
|
+
})
|
|
88
83
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
if (dialRequest == null) {
|
|
85
|
+
throw new ProtocolError('Did not receive DialRequest message on incoming dial request stream')
|
|
86
|
+
}
|
|
92
87
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
if (dialRequest.addrs.length === 0) {
|
|
89
|
+
throw new ProtocolError('Did not receive any addresses to dial')
|
|
90
|
+
}
|
|
96
91
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
|
|
125
|
-
throw new ProtocolError(`Requested address had private IP "${ma}"`)
|
|
126
|
-
}
|
|
113
|
+
const ip = getIpAddress(ma)
|
|
127
114
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
119
|
+
if (isPrivateIp(ip)) {
|
|
120
|
+
throw new ProtocolError(`Requested address had private IP "${ma}"`)
|
|
121
|
+
}
|
|
139
122
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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:
|
|
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')
|
package/dist/typedoc-urls.json
DELETED
|
@@ -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
|
-
}
|