libp2p 0.42.2 → 0.43.0

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 (295) hide show
  1. package/README.md +4 -4
  2. package/dist/index.min.js +29 -29
  3. package/dist/src/address-manager/index.d.ts +1 -10
  4. package/dist/src/address-manager/index.d.ts.map +1 -1
  5. package/dist/src/address-manager/index.js +46 -29
  6. package/dist/src/address-manager/index.js.map +1 -1
  7. package/dist/src/autonat/constants.d.ts +4 -0
  8. package/dist/src/autonat/constants.d.ts.map +1 -0
  9. package/dist/src/autonat/constants.js +4 -0
  10. package/dist/src/autonat/constants.js.map +1 -0
  11. package/dist/src/autonat/index.d.ts +64 -0
  12. package/dist/src/autonat/index.d.ts.map +1 -0
  13. package/dist/src/autonat/index.js +417 -0
  14. package/dist/src/autonat/index.js.map +1 -0
  15. package/dist/src/autonat/pb/index.d.ts +57 -0
  16. package/dist/src/autonat/pb/index.d.ts.map +1 -0
  17. package/dist/src/autonat/pb/index.js +250 -0
  18. package/dist/src/autonat/pb/index.js.map +1 -0
  19. package/dist/src/circuit/constants.d.ts +31 -6
  20. package/dist/src/circuit/constants.d.ts.map +1 -1
  21. package/dist/src/circuit/constants.js +37 -7
  22. package/dist/src/circuit/constants.js.map +1 -1
  23. package/dist/src/circuit/index.d.ts +16 -61
  24. package/dist/src/circuit/index.d.ts.map +1 -1
  25. package/dist/src/circuit/index.js +2 -68
  26. package/dist/src/circuit/index.js.map +1 -1
  27. package/dist/src/circuit/pb/index.d.ts +83 -43
  28. package/dist/src/circuit/pb/index.d.ts.map +1 -1
  29. package/dist/src/circuit/pb/index.js +363 -127
  30. package/dist/src/circuit/pb/index.js.map +1 -1
  31. package/dist/src/circuit/server/advert-service.d.ts +43 -0
  32. package/dist/src/circuit/server/advert-service.d.ts.map +1 -0
  33. package/dist/src/circuit/server/advert-service.js +69 -0
  34. package/dist/src/circuit/server/advert-service.js.map +1 -0
  35. package/dist/src/circuit/server/index.d.ts +60 -0
  36. package/dist/src/circuit/server/index.d.ts.map +1 -0
  37. package/dist/src/circuit/server/index.js +287 -0
  38. package/dist/src/circuit/server/index.js.map +1 -0
  39. package/dist/src/circuit/server/reservation-store.d.ts +49 -0
  40. package/dist/src/circuit/server/reservation-store.d.ts.map +1 -0
  41. package/dist/src/circuit/server/reservation-store.js +57 -0
  42. package/dist/src/circuit/server/reservation-store.js.map +1 -0
  43. package/dist/src/circuit/server/reservation-voucher.d.ts +18 -0
  44. package/dist/src/circuit/server/reservation-voucher.d.ts.map +1 -0
  45. package/dist/src/circuit/server/reservation-voucher.js +33 -0
  46. package/dist/src/circuit/server/reservation-voucher.js.map +1 -0
  47. package/dist/src/circuit/transport/discovery.d.ts +45 -0
  48. package/dist/src/circuit/transport/discovery.d.ts.map +1 -0
  49. package/dist/src/circuit/transport/discovery.js +82 -0
  50. package/dist/src/circuit/transport/discovery.js.map +1 -0
  51. package/dist/src/circuit/transport/index.d.ts +33 -0
  52. package/dist/src/circuit/transport/index.d.ts.map +1 -0
  53. package/dist/src/circuit/transport/index.js +225 -0
  54. package/dist/src/circuit/transport/index.js.map +1 -0
  55. package/dist/src/circuit/transport/listener.d.ts +9 -0
  56. package/dist/src/circuit/transport/listener.d.ts.map +1 -0
  57. package/dist/src/circuit/transport/listener.js +76 -0
  58. package/dist/src/circuit/transport/listener.js.map +1 -0
  59. package/dist/src/circuit/transport/reservation-store.d.ts +60 -0
  60. package/dist/src/circuit/transport/reservation-store.d.ts.map +1 -0
  61. package/dist/src/circuit/transport/reservation-store.js +165 -0
  62. package/dist/src/circuit/transport/reservation-store.js.map +1 -0
  63. package/dist/src/circuit/utils.d.ts +7 -0
  64. package/dist/src/circuit/utils.d.ts.map +1 -1
  65. package/dist/src/circuit/utils.js +87 -0
  66. package/dist/src/circuit/utils.js.map +1 -1
  67. package/dist/src/components.d.ts +2 -1
  68. package/dist/src/components.d.ts.map +1 -1
  69. package/dist/src/components.js +13 -13
  70. package/dist/src/components.js.map +1 -1
  71. package/dist/src/config.d.ts.map +1 -1
  72. package/dist/src/config.js +21 -25
  73. package/dist/src/config.js.map +1 -1
  74. package/dist/src/connection/index.d.ts +2 -2
  75. package/dist/src/connection/index.d.ts.map +1 -1
  76. package/dist/src/connection/index.js +4 -4
  77. package/dist/src/connection/index.js.map +1 -1
  78. package/dist/src/connection-manager/auto-dialler.d.ts +0 -4
  79. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  80. package/dist/src/connection-manager/auto-dialler.js +18 -18
  81. package/dist/src/connection-manager/auto-dialler.js.map +1 -1
  82. package/dist/src/connection-manager/dialer/dial-request.d.ts.map +1 -1
  83. package/dist/src/connection-manager/dialer/dial-request.js +13 -6
  84. package/dist/src/connection-manager/dialer/dial-request.js.map +1 -1
  85. package/dist/src/connection-manager/dialer/index.d.ts +10 -1
  86. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  87. package/dist/src/connection-manager/dialer/index.js +24 -9
  88. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  89. package/dist/src/connection-manager/index.d.ts +1 -4
  90. package/dist/src/connection-manager/index.d.ts.map +1 -1
  91. package/dist/src/connection-manager/index.js +8 -5
  92. package/dist/src/connection-manager/index.js.map +1 -1
  93. package/dist/src/connection-manager/latency-monitor.d.ts.map +1 -1
  94. package/dist/src/connection-manager/latency-monitor.js +1 -1
  95. package/dist/src/connection-manager/latency-monitor.js.map +1 -1
  96. package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +1 -1
  97. package/dist/src/content-routing/index.d.ts +6 -4
  98. package/dist/src/content-routing/index.d.ts.map +1 -1
  99. package/dist/src/content-routing/index.js +9 -9
  100. package/dist/src/content-routing/index.js.map +1 -1
  101. package/dist/src/content-routing/utils.d.ts +3 -3
  102. package/dist/src/content-routing/utils.d.ts.map +1 -1
  103. package/dist/src/content-routing/utils.js +2 -2
  104. package/dist/src/content-routing/utils.js.map +1 -1
  105. package/dist/src/dht/dht-content-routing.d.ts +2 -1
  106. package/dist/src/dht/dht-content-routing.d.ts.map +1 -1
  107. package/dist/src/dht/dht-content-routing.js +2 -2
  108. package/dist/src/dht/dht-content-routing.js.map +1 -1
  109. package/dist/src/dht/dht-peer-routing.d.ts +3 -2
  110. package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
  111. package/dist/src/dht/dht-peer-routing.js +2 -2
  112. package/dist/src/dht/dht-peer-routing.js.map +1 -1
  113. package/dist/src/dht/dummy-dht.d.ts +1 -1
  114. package/dist/src/dht/dummy-dht.d.ts.map +1 -1
  115. package/dist/src/dht/dummy-dht.js +12 -12
  116. package/dist/src/dht/dummy-dht.js.map +1 -1
  117. package/dist/src/errors.d.ts +2 -1
  118. package/dist/src/errors.d.ts.map +1 -1
  119. package/dist/src/errors.js +1 -0
  120. package/dist/src/errors.js.map +1 -1
  121. package/dist/src/fetch/index.d.ts.map +1 -1
  122. package/dist/src/fetch/index.js +6 -6
  123. package/dist/src/fetch/index.js.map +1 -1
  124. package/dist/src/fetch/pb/proto.d.ts +3 -3
  125. package/dist/src/fetch/pb/proto.d.ts.map +1 -1
  126. package/dist/src/fetch/pb/proto.js +4 -3
  127. package/dist/src/fetch/pb/proto.js.map +1 -1
  128. package/dist/src/get-peer.js +2 -2
  129. package/dist/src/get-peer.js.map +1 -1
  130. package/dist/src/identify/index.d.ts +3 -1
  131. package/dist/src/identify/index.d.ts.map +1 -1
  132. package/dist/src/identify/index.js +19 -14
  133. package/dist/src/identify/index.js.map +1 -1
  134. package/dist/src/identify/pb/message.d.ts +2 -2
  135. package/dist/src/identify/pb/message.d.ts.map +1 -1
  136. package/dist/src/identify/pb/message.js +1 -0
  137. package/dist/src/identify/pb/message.js.map +1 -1
  138. package/dist/src/index.d.ts +14 -8
  139. package/dist/src/index.d.ts.map +1 -1
  140. package/dist/src/index.js.map +1 -1
  141. package/dist/src/insecure/index.d.ts.map +1 -1
  142. package/dist/src/insecure/index.js.map +1 -1
  143. package/dist/src/insecure/pb/proto.d.ts +3 -3
  144. package/dist/src/insecure/pb/proto.d.ts.map +1 -1
  145. package/dist/src/insecure/pb/proto.js +4 -5
  146. package/dist/src/insecure/pb/proto.js.map +1 -1
  147. package/dist/src/libp2p.d.ts +7 -3
  148. package/dist/src/libp2p.d.ts.map +1 -1
  149. package/dist/src/libp2p.js +35 -35
  150. package/dist/src/libp2p.js.map +1 -1
  151. package/dist/src/nat-manager.d.ts.map +1 -1
  152. package/dist/src/nat-manager.js +5 -3
  153. package/dist/src/nat-manager.js.map +1 -1
  154. package/dist/src/peer-record-updater.d.ts.map +1 -1
  155. package/dist/src/peer-routing.d.ts.map +1 -1
  156. package/dist/src/peer-routing.js +5 -5
  157. package/dist/src/peer-routing.js.map +1 -1
  158. package/dist/src/ping/index.d.ts.map +1 -1
  159. package/dist/src/ping/index.js +2 -2
  160. package/dist/src/ping/index.js.map +1 -1
  161. package/dist/src/pnet/crypto.d.ts +1 -1
  162. package/dist/src/pnet/crypto.d.ts.map +1 -1
  163. package/dist/src/pnet/crypto.js +1 -1
  164. package/dist/src/pnet/crypto.js.map +1 -1
  165. package/dist/src/pnet/index.js +3 -3
  166. package/dist/src/pnet/index.js.map +1 -1
  167. package/dist/src/pnet/key-generator.d.ts.map +1 -1
  168. package/dist/src/pubsub/dummy-pubsub.js +9 -9
  169. package/dist/src/pubsub/dummy-pubsub.js.map +1 -1
  170. package/dist/src/registrar.d.ts.map +1 -1
  171. package/dist/src/registrar.js +4 -4
  172. package/dist/src/registrar.js.map +1 -1
  173. package/dist/src/transport-manager.d.ts.map +1 -1
  174. package/dist/src/transport-manager.js +8 -9
  175. package/dist/src/transport-manager.js.map +1 -1
  176. package/dist/src/upgrader.d.ts +2 -1
  177. package/dist/src/upgrader.d.ts.map +1 -1
  178. package/dist/src/upgrader.js +38 -33
  179. package/dist/src/upgrader.js.map +1 -1
  180. package/dist/typedoc-urls.json +19 -6
  181. package/package.json +36 -33
  182. package/src/address-manager/index.ts +62 -35
  183. package/src/autonat/constants.ts +4 -0
  184. package/src/autonat/index.ts +567 -0
  185. package/src/autonat/pb/index.proto +35 -0
  186. package/src/autonat/pb/index.ts +320 -0
  187. package/src/circuit/constants.ts +48 -7
  188. package/src/circuit/index.ts +17 -129
  189. package/src/circuit/pb/index.proto +57 -32
  190. package/src/circuit/pb/index.ts +448 -138
  191. package/src/circuit/server/advert-service.ts +108 -0
  192. package/src/circuit/server/index.ts +421 -0
  193. package/src/circuit/server/reservation-store.ts +111 -0
  194. package/src/circuit/server/reservation-voucher.ts +51 -0
  195. package/src/circuit/transport/discovery.ts +127 -0
  196. package/src/circuit/transport/index.ts +325 -0
  197. package/src/circuit/transport/listener.ts +99 -0
  198. package/src/circuit/transport/reservation-store.ts +249 -0
  199. package/src/circuit/utils.ts +108 -0
  200. package/src/components.ts +22 -21
  201. package/src/config.ts +21 -25
  202. package/src/connection/index.ts +10 -10
  203. package/src/connection-manager/auto-dialler.ts +36 -40
  204. package/src/connection-manager/dialer/dial-request.ts +13 -6
  205. package/src/connection-manager/dialer/index.ts +34 -15
  206. package/src/connection-manager/index.ts +22 -23
  207. package/src/connection-manager/latency-monitor.ts +9 -9
  208. package/src/connection-manager/visibility-change-emitter.ts +4 -4
  209. package/src/content-routing/index.ts +18 -16
  210. package/src/content-routing/utils.ts +5 -5
  211. package/src/dht/dht-content-routing.ts +5 -4
  212. package/src/dht/dht-peer-routing.ts +5 -4
  213. package/src/dht/dummy-dht.ts +13 -13
  214. package/src/errors.ts +2 -1
  215. package/src/fetch/index.ts +13 -13
  216. package/src/fetch/pb/proto.ts +8 -7
  217. package/src/get-peer.ts +3 -3
  218. package/src/identify/index.ts +29 -24
  219. package/src/identify/pb/message.ts +3 -2
  220. package/src/index.ts +15 -8
  221. package/src/insecure/index.ts +2 -1
  222. package/src/insecure/pb/proto.ts +8 -9
  223. package/src/libp2p.ts +52 -46
  224. package/src/nat-manager.ts +11 -9
  225. package/src/peer-record-updater.ts +4 -4
  226. package/src/peer-routing.ts +9 -9
  227. package/src/ping/index.ts +6 -6
  228. package/src/pnet/crypto.ts +3 -3
  229. package/src/pnet/index.ts +3 -3
  230. package/src/pnet/key-generator.ts +1 -1
  231. package/src/pubsub/dummy-pubsub.ts +9 -9
  232. package/src/registrar.ts +12 -12
  233. package/src/transport-manager.ts +17 -18
  234. package/src/upgrader.ts +43 -42
  235. package/src/version.ts +1 -1
  236. package/dist/src/circuit/auto-relay.d.ts +0 -46
  237. package/dist/src/circuit/auto-relay.d.ts.map +0 -1
  238. package/dist/src/circuit/auto-relay.js +0 -220
  239. package/dist/src/circuit/auto-relay.js.map +0 -1
  240. package/dist/src/circuit/circuit/hop.d.ts +0 -42
  241. package/dist/src/circuit/circuit/hop.d.ts.map +0 -1
  242. package/dist/src/circuit/circuit/hop.js +0 -142
  243. package/dist/src/circuit/circuit/hop.js.map +0 -1
  244. package/dist/src/circuit/circuit/stop.d.ts +0 -24
  245. package/dist/src/circuit/circuit/stop.d.ts.map +0 -1
  246. package/dist/src/circuit/circuit/stop.js +0 -51
  247. package/dist/src/circuit/circuit/stop.js.map +0 -1
  248. package/dist/src/circuit/circuit/stream-handler.d.ts +0 -40
  249. package/dist/src/circuit/circuit/stream-handler.d.ts.map +0 -1
  250. package/dist/src/circuit/circuit/stream-handler.js +0 -59
  251. package/dist/src/circuit/circuit/stream-handler.js.map +0 -1
  252. package/dist/src/circuit/circuit/utils.d.ts +0 -7
  253. package/dist/src/circuit/circuit/utils.d.ts.map +0 -1
  254. package/dist/src/circuit/circuit/utils.js +0 -43
  255. package/dist/src/circuit/circuit/utils.js.map +0 -1
  256. package/dist/src/circuit/listener.d.ts +0 -9
  257. package/dist/src/circuit/listener.d.ts.map +0 -1
  258. package/dist/src/circuit/listener.js +0 -62
  259. package/dist/src/circuit/listener.js.map +0 -1
  260. package/dist/src/circuit/multicodec.d.ts +0 -2
  261. package/dist/src/circuit/multicodec.d.ts.map +0 -1
  262. package/dist/src/circuit/multicodec.js +0 -2
  263. package/dist/src/circuit/multicodec.js.map +0 -1
  264. package/dist/src/circuit/transport.d.ts +0 -51
  265. package/dist/src/circuit/transport.d.ts.map +0 -1
  266. package/dist/src/circuit/transport.js +0 -223
  267. package/dist/src/circuit/transport.js.map +0 -1
  268. package/dist/src/keychain/cms.d.ts +0 -33
  269. package/dist/src/keychain/cms.d.ts.map +0 -1
  270. package/dist/src/keychain/cms.js +0 -129
  271. package/dist/src/keychain/cms.js.map +0 -1
  272. package/dist/src/keychain/index.d.ts +0 -151
  273. package/dist/src/keychain/index.d.ts.map +0 -1
  274. package/dist/src/keychain/index.js +0 -519
  275. package/dist/src/keychain/index.js.map +0 -1
  276. package/dist/src/keychain/util.d.ts +0 -21
  277. package/dist/src/keychain/util.d.ts.map +0 -1
  278. package/dist/src/keychain/util.js +0 -79
  279. package/dist/src/keychain/util.js.map +0 -1
  280. package/src/circuit/IMPLEMENTATION_NOTES.md +0 -128
  281. package/src/circuit/README.md +0 -111
  282. package/src/circuit/auto-relay.ts +0 -292
  283. package/src/circuit/circuit/hop.ts +0 -220
  284. package/src/circuit/circuit/stop.ts +0 -83
  285. package/src/circuit/circuit/stream-handler.ts +0 -87
  286. package/src/circuit/circuit/utils.ts +0 -44
  287. package/src/circuit/listener.ts +0 -83
  288. package/src/circuit/multicodec.ts +0 -2
  289. package/src/circuit/transport.ts +0 -278
  290. package/src/keychain/README.md +0 -55
  291. package/src/keychain/cms.ts +0 -150
  292. package/src/keychain/doc/private-key.png +0 -0
  293. package/src/keychain/doc/private-key.xml +0 -1
  294. package/src/keychain/index.ts +0 -629
  295. package/src/keychain/util.ts +0 -82
@@ -0,0 +1,567 @@
1
+ import type { AddressManager } from '@libp2p/interface-address-manager'
2
+ import type { Connection } from '@libp2p/interface-connection'
3
+ import type { ConnectionManager, Dialer } from '@libp2p/interface-connection-manager'
4
+ import type { PeerId } from '@libp2p/interface-peer-id'
5
+ import type { PeerInfo } from '@libp2p/interface-peer-info'
6
+ import type { PeerRouting } from '@libp2p/interface-peer-routing'
7
+ import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
8
+ import type { TransportManager } from '@libp2p/interface-transport'
9
+ import type { Startable } from '@libp2p/interfaces/startable'
10
+ import { logger } from '@libp2p/logger'
11
+ import { peerIdFromBytes } from '@libp2p/peer-id'
12
+ import { createEd25519PeerId } from '@libp2p/peer-id-factory'
13
+ import { multiaddr, protocols } from '@multiformats/multiaddr'
14
+ import { abortableDuplex } from 'abortable-iterator'
15
+ import { setMaxListeners } from 'events'
16
+ import first from 'it-first'
17
+ import * as lp from 'it-length-prefixed'
18
+ import map from 'it-map'
19
+ import parallel from 'it-parallel'
20
+ import { pipe } from 'it-pipe'
21
+ import isPrivateIp from 'private-ip'
22
+ import { TimeoutController } from 'timeout-abort-controller'
23
+ import {
24
+ PROTOCOL
25
+ } from './constants.js'
26
+ import { Message } from './pb/index.js'
27
+
28
+ const log = logger('libp2p:autonat')
29
+
30
+ // if more than 3 peers manage to dial us on what we believe to be our external
31
+ // IP then we are convinced that it is, in fact, our external IP
32
+ // https://github.com/libp2p/specs/blob/master/autonat/README.md#autonat-protocol
33
+ const REQUIRED_SUCCESSFUL_DIALS = 4
34
+
35
+ // Wait this long before we start to query autonat nodes
36
+ const AUTONAT_STARTUP_DELAY = 5000
37
+
38
+ // Only try to verify our external address this often
39
+ const AUTONAT_REFRESH_INTERVAL = 60000
40
+
41
+ export interface AutonatServiceInit {
42
+ /**
43
+ * Allows overriding the protocol prefix used
44
+ */
45
+ protocolPrefix: string
46
+
47
+ /**
48
+ * How long we should wait for a remote peer to verify our external address
49
+ */
50
+ timeout: number
51
+
52
+ /**
53
+ * How long to wait after startup before trying to verify our external address
54
+ */
55
+ startupDelay: number
56
+
57
+ /**
58
+ * Verify our external addresses this often
59
+ */
60
+ refreshInterval: number
61
+
62
+ /**
63
+ * How many parallel inbound autonat streams we allow per-connection
64
+ */
65
+ maxInboundStreams: number
66
+
67
+ /**
68
+ * How many parallel outbound autonat streams we allow per-connection
69
+ */
70
+ maxOutboundStreams: number
71
+ }
72
+
73
+ export interface DefaultAutonatComponents {
74
+ registrar: Registrar
75
+ addressManager: AddressManager
76
+ transportManager: TransportManager
77
+ dialer: Dialer
78
+ peerId: PeerId
79
+ connectionManager: ConnectionManager
80
+ peerRouting: PeerRouting
81
+ }
82
+
83
+ export class AutonatService implements Startable {
84
+ private readonly components: DefaultAutonatComponents
85
+ private readonly _init: AutonatServiceInit
86
+ private readonly startupDelay: number
87
+ private readonly refreshInterval: number
88
+ private verifyAddressTimeout?: ReturnType<typeof setTimeout>
89
+ private started: boolean
90
+
91
+ constructor (components: DefaultAutonatComponents, init: AutonatServiceInit) {
92
+ this.components = components
93
+ this.started = false
94
+ this._init = init
95
+ this.startupDelay = init.startupDelay ?? AUTONAT_STARTUP_DELAY
96
+ this.refreshInterval = init.refreshInterval ?? AUTONAT_REFRESH_INTERVAL
97
+
98
+ this._verifyExternalAddresses = this._verifyExternalAddresses.bind(this)
99
+ }
100
+
101
+ isStarted (): boolean {
102
+ return this.started
103
+ }
104
+
105
+ async start (): Promise<void> {
106
+ if (this.started) {
107
+ return
108
+ }
109
+
110
+ await this.components.registrar.handle(PROTOCOL, (data) => {
111
+ void this.handleIncomingAutonatStream(data)
112
+ .catch(err => {
113
+ log.error(err)
114
+ })
115
+ }, {
116
+ maxInboundStreams: this._init.maxInboundStreams,
117
+ maxOutboundStreams: this._init.maxOutboundStreams
118
+ })
119
+
120
+ this.verifyAddressTimeout = setTimeout(this._verifyExternalAddresses, this.startupDelay)
121
+
122
+ this.started = true
123
+ }
124
+
125
+ async stop (): Promise<void> {
126
+ await this.components.registrar.unhandle(PROTOCOL)
127
+ clearTimeout(this.verifyAddressTimeout)
128
+
129
+ this.started = false
130
+ }
131
+
132
+ /**
133
+ * Handle an incoming autonat request
134
+ */
135
+ async handleIncomingAutonatStream (data: IncomingStreamData): Promise<void> {
136
+ const controller = new TimeoutController(this._init.timeout)
137
+
138
+ // this controller may be used while dialing lots of peers so prevent MaxListenersExceededWarning
139
+ // appearing in the console
140
+ try {
141
+ // fails on node < 15.4
142
+ setMaxListeners?.(Infinity, controller.signal)
143
+ } catch {}
144
+
145
+ const ourHosts = this.components.addressManager.getAddresses()
146
+ .map(ma => ma.toOptions().host)
147
+
148
+ try {
149
+ const source = abortableDuplex(data.stream, controller.signal)
150
+ const self = this
151
+
152
+ await pipe(
153
+ source,
154
+ lp.decode(),
155
+ async function * (stream) {
156
+ const buf = await first(stream)
157
+
158
+ if (buf == null) {
159
+ log('No message received')
160
+ yield Message.encode({
161
+ type: Message.MessageType.DIAL_RESPONSE,
162
+ dialResponse: {
163
+ status: Message.ResponseStatus.E_BAD_REQUEST,
164
+ statusText: 'No message was sent'
165
+ }
166
+ })
167
+
168
+ return
169
+ }
170
+
171
+ let request: Message
172
+
173
+ try {
174
+ request = Message.decode(buf)
175
+ } catch (err) {
176
+ log.error('Could not decode message', err)
177
+
178
+ yield Message.encode({
179
+ type: Message.MessageType.DIAL_RESPONSE,
180
+ dialResponse: {
181
+ status: Message.ResponseStatus.E_BAD_REQUEST,
182
+ statusText: 'Could not decode message'
183
+ }
184
+ })
185
+
186
+ return
187
+ }
188
+
189
+ const dialRequest = request.dial
190
+
191
+ if (dialRequest == null) {
192
+ log.error('Dial was missing from message')
193
+
194
+ yield Message.encode({
195
+ type: Message.MessageType.DIAL_RESPONSE,
196
+ dialResponse: {
197
+ status: Message.ResponseStatus.E_BAD_REQUEST,
198
+ statusText: 'No Dial message found in message'
199
+ }
200
+ })
201
+
202
+ return
203
+ }
204
+
205
+ let peerId: PeerId
206
+ const peer = dialRequest.peer
207
+
208
+ if (peer == null || peer.id == null) {
209
+ log.error('PeerId missing from message')
210
+
211
+ yield Message.encode({
212
+ type: Message.MessageType.DIAL_RESPONSE,
213
+ dialResponse: {
214
+ status: Message.ResponseStatus.E_BAD_REQUEST,
215
+ statusText: 'missing peer info'
216
+ }
217
+ })
218
+
219
+ return
220
+ }
221
+
222
+ try {
223
+ peerId = peerIdFromBytes(peer.id)
224
+ } catch (err) {
225
+ log.error('Invalid PeerId', err)
226
+
227
+ yield Message.encode({
228
+ type: Message.MessageType.DIAL_RESPONSE,
229
+ dialResponse: {
230
+ status: Message.ResponseStatus.E_BAD_REQUEST,
231
+ statusText: 'bad peer id'
232
+ }
233
+ })
234
+
235
+ return
236
+ }
237
+
238
+ log('Incoming request from %p', peerId)
239
+
240
+ // reject any dial requests that arrive via relays
241
+ if (!data.connection.remotePeer.equals(peerId)) {
242
+ log('Target peer %p did not equal sending peer %p', peerId, data.connection.remotePeer)
243
+
244
+ yield Message.encode({
245
+ type: Message.MessageType.DIAL_RESPONSE,
246
+ dialResponse: {
247
+ status: Message.ResponseStatus.E_BAD_REQUEST,
248
+ statusText: 'peer id mismatch'
249
+ }
250
+ })
251
+
252
+ return
253
+ }
254
+
255
+ // get a list of multiaddrs to dial
256
+ const multiaddrs = peer.addrs
257
+ .map(buf => multiaddr(buf))
258
+ .filter(ma => {
259
+ const isFromSameHost = ma.toOptions().host === data.connection.remoteAddr.toOptions().host
260
+
261
+ log.trace('Request to dial %s was sent from %s is same host %s', ma, data.connection.remoteAddr, isFromSameHost)
262
+ // skip any Multiaddrs where the target node's IP does not match the sending node's IP
263
+ return isFromSameHost
264
+ })
265
+ .filter(ma => {
266
+ const host = ma.toOptions().host
267
+ const isPublicIp = !(isPrivateIp(host) ?? false)
268
+
269
+ log.trace('Host %s was public %s', host, isPublicIp)
270
+ // don't try to dial private addresses
271
+ return isPublicIp
272
+ })
273
+ .filter(ma => {
274
+ const host = ma.toOptions().host
275
+ const isNotOurHost = !ourHosts.includes(host)
276
+
277
+ log.trace('Host %s was not our host %s', host, isNotOurHost)
278
+ // don't try to dial nodes on the same host as us
279
+ return isNotOurHost
280
+ })
281
+ .filter(ma => {
282
+ const isSupportedTransport = Boolean(self.components.transportManager.transportForMultiaddr(ma))
283
+
284
+ log.trace('Transport for %s is supported %s', ma, isSupportedTransport)
285
+ // skip any Multiaddrs that have transports we do not support
286
+ return isSupportedTransport
287
+ })
288
+ .map(ma => {
289
+ if (ma.getPeerId() == null) {
290
+ // make sure we have the PeerId as part of the Multiaddr
291
+ ma = ma.encapsulate(`/p2p/${peerId.toString()}`)
292
+ }
293
+
294
+ return ma
295
+ })
296
+
297
+ // make sure we have something to dial
298
+ if (multiaddrs.length === 0) {
299
+ log('No valid multiaddrs for %p in message', peerId)
300
+
301
+ yield Message.encode({
302
+ type: Message.MessageType.DIAL_RESPONSE,
303
+ dialResponse: {
304
+ status: Message.ResponseStatus.E_DIAL_REFUSED,
305
+ statusText: 'no dialable addresses'
306
+ }
307
+ })
308
+
309
+ return
310
+ }
311
+
312
+ log('Dial multiaddrs %s for peer %p', multiaddrs.map(ma => ma.toString()).join(', '), peerId)
313
+
314
+ let errorMessage = ''
315
+ let lastMultiaddr = multiaddrs[0]
316
+
317
+ for await (const multiaddr of multiaddrs) {
318
+ let connection: Connection | undefined
319
+ lastMultiaddr = multiaddr
320
+
321
+ try {
322
+ // use the dialer so we can dial a specific multiaddr instead of every known
323
+ // multiaddr for the peer
324
+ connection = await self.components.dialer.dial(multiaddr, {
325
+ signal: controller.signal
326
+ })
327
+
328
+ if (!connection.remoteAddr.equals(multiaddr)) {
329
+ log.error('Tried to dial %s but dialed %s', multiaddr, connection.remoteAddr)
330
+ throw new Error('Unexpected remote address')
331
+ }
332
+
333
+ log('Success %p', peerId)
334
+
335
+ yield Message.encode({
336
+ type: Message.MessageType.DIAL_RESPONSE,
337
+ dialResponse: {
338
+ status: Message.ResponseStatus.OK,
339
+ addr: connection.remoteAddr.decapsulateCode(protocols('p2p').code).bytes
340
+ }
341
+ })
342
+
343
+ return
344
+ } catch (err: any) {
345
+ log('Could not dial %p', peerId, err)
346
+ errorMessage = err.message
347
+ } finally {
348
+ if (connection != null) {
349
+ await connection.close()
350
+ }
351
+ }
352
+ }
353
+
354
+ yield Message.encode({
355
+ type: Message.MessageType.DIAL_RESPONSE,
356
+ dialResponse: {
357
+ status: Message.ResponseStatus.E_DIAL_ERROR,
358
+ statusText: errorMessage,
359
+ addr: lastMultiaddr.bytes
360
+ }
361
+ })
362
+ },
363
+ lp.encode(),
364
+ // pipe to the stream, not the abortable source other wise we
365
+ // can't tell the remote when a dial timed out..
366
+ data.stream
367
+ )
368
+ } finally {
369
+ controller.clear()
370
+ }
371
+ }
372
+
373
+ _verifyExternalAddresses (): void {
374
+ void this.verifyExternalAddresses()
375
+ .catch(err => {
376
+ log.error(err)
377
+ })
378
+ }
379
+
380
+ /**
381
+ * Our multicodec topology noticed a new peer that supports autonat
382
+ */
383
+ async verifyExternalAddresses (): Promise<void> {
384
+ clearTimeout(this.verifyAddressTimeout)
385
+
386
+ // Do not try to push if we are not running
387
+ if (!this.isStarted()) {
388
+ return
389
+ }
390
+
391
+ const addressManager = this.components.addressManager
392
+
393
+ const multiaddrs = addressManager.getObservedAddrs()
394
+ .filter(ma => {
395
+ const options = ma.toOptions()
396
+
397
+ return !(isPrivateIp(options.host) ?? false)
398
+ })
399
+
400
+ if (multiaddrs.length === 0) {
401
+ log('No public addresses found, not requesting verification')
402
+ this.verifyAddressTimeout = setTimeout(this._verifyExternalAddresses, this.refreshInterval)
403
+
404
+ return
405
+ }
406
+
407
+ const controller = new TimeoutController(this._init.timeout)
408
+
409
+ // this controller may be used while dialing lots of peers so prevent MaxListenersExceededWarning
410
+ // appearing in the console
411
+ try {
412
+ // fails on node < 15.4
413
+ setMaxListeners?.(Infinity, controller.signal)
414
+ } catch {}
415
+
416
+ const self = this
417
+
418
+ try {
419
+ log('verify multiaddrs %s', multiaddrs.map(ma => ma.toString()).join(', '))
420
+
421
+ const request = Message.encode({
422
+ type: Message.MessageType.DIAL,
423
+ dial: {
424
+ peer: {
425
+ id: this.components.peerId.toBytes(),
426
+ addrs: multiaddrs.map(map => map.bytes)
427
+ }
428
+ }
429
+ })
430
+ // find some random peers
431
+ const randomPeer = await createEd25519PeerId()
432
+ const randomCid = randomPeer.toBytes()
433
+
434
+ const results: Record<string, { success: number, failure: number }> = {}
435
+ const networkSegments: string[] = []
436
+
437
+ async function verifyAddress (peer: PeerInfo): Promise<Message.DialResponse | undefined> {
438
+ try {
439
+ log('Asking %p to verify multiaddr', peer.id)
440
+
441
+ const connection = await self.components.connectionManager.openConnection(peer.id, {
442
+ signal: controller.signal
443
+ })
444
+
445
+ const stream = await connection.newStream(PROTOCOL, {
446
+ signal: controller.signal
447
+ })
448
+ const source = abortableDuplex(stream, controller.signal)
449
+
450
+ const buf = await pipe(
451
+ [request],
452
+ lp.encode(),
453
+ source,
454
+ lp.decode(),
455
+ async (stream) => await first(stream)
456
+ )
457
+ if (buf == null) {
458
+ log('No response received from %s', connection.remotePeer)
459
+ return undefined
460
+ }
461
+ const response = Message.decode(buf)
462
+
463
+ if (response.type !== Message.MessageType.DIAL_RESPONSE || response.dialResponse == null) {
464
+ log('Invalid autonat response from %s', connection.remotePeer)
465
+ return undefined
466
+ }
467
+
468
+ if (response.dialResponse.status === Message.ResponseStatus.OK) {
469
+ // make sure we use different network segments
470
+ const options = connection.remoteAddr.toOptions()
471
+ let segment: string
472
+
473
+ if (options.family === 4) {
474
+ const octets = options.host.split('.')
475
+ segment = octets[0]
476
+ } else if (options.family === 6) {
477
+ const octets = options.host.split(':')
478
+ segment = octets[0]
479
+ } else {
480
+ log('Remote address "%s" was not IP4 or IP6?', options.host)
481
+ return undefined
482
+ }
483
+
484
+ if (networkSegments.includes(segment)) {
485
+ log('Already have response from network segment %d - %s', segment, options.host)
486
+ return undefined
487
+ }
488
+
489
+ networkSegments.push(segment)
490
+ }
491
+
492
+ return response.dialResponse
493
+ } catch (err) {
494
+ log.error(err)
495
+ }
496
+ }
497
+
498
+ for await (const dialResponse of parallel(map(this.components.peerRouting.getClosestPeers(randomCid, {
499
+ signal: controller.signal
500
+ }), (peer) => async () => await verifyAddress(peer)), {
501
+ concurrency: REQUIRED_SUCCESSFUL_DIALS
502
+ })) {
503
+ try {
504
+ if (dialResponse == null) {
505
+ continue
506
+ }
507
+
508
+ // they either told us which address worked/didn't work, or we only sent them one address
509
+ const addr = dialResponse.addr == null ? multiaddrs[0] : multiaddr(dialResponse.addr)
510
+
511
+ log('Autonat response for %s is %s', addr, dialResponse.status)
512
+
513
+ if (dialResponse.status === Message.ResponseStatus.E_BAD_REQUEST) {
514
+ // the remote could not parse our request
515
+ continue
516
+ }
517
+
518
+ if (dialResponse.status === Message.ResponseStatus.E_DIAL_REFUSED) {
519
+ // the remote could not honour our request
520
+ continue
521
+ }
522
+
523
+ if (dialResponse.addr == null && multiaddrs.length > 1) {
524
+ // we sent the remote multiple addrs but they didn't tell us which ones worked/didn't work
525
+ continue
526
+ }
527
+
528
+ if (!multiaddrs.some(ma => ma.equals(addr))) {
529
+ log('Peer reported %s as %s but it was not in our observed address list', addr, dialResponse.status)
530
+ continue
531
+ }
532
+
533
+ const addrStr = addr.toString()
534
+
535
+ if (results[addrStr] == null) {
536
+ results[addrStr] = { success: 0, failure: 0 }
537
+ }
538
+
539
+ if (dialResponse.status === Message.ResponseStatus.OK) {
540
+ results[addrStr].success++
541
+ } else if (dialResponse.status === Message.ResponseStatus.E_DIAL_ERROR) {
542
+ results[addrStr].failure++
543
+ }
544
+
545
+ if (results[addrStr].success === REQUIRED_SUCCESSFUL_DIALS) {
546
+ // we are now convinced
547
+ log('%s is externally dialable', addr)
548
+ addressManager.confirmObservedAddr(addr)
549
+ return
550
+ }
551
+
552
+ if (results[addrStr].failure === REQUIRED_SUCCESSFUL_DIALS) {
553
+ // we are now unconvinced
554
+ log('%s is not externally dialable', addr)
555
+ addressManager.removeObservedAddr(addr)
556
+ return
557
+ }
558
+ } catch (err) {
559
+ log.error('Could not verify external address', err)
560
+ }
561
+ }
562
+ } finally {
563
+ controller.clear()
564
+ this.verifyAddressTimeout = setTimeout(this._verifyExternalAddresses, this.refreshInterval)
565
+ }
566
+ }
567
+ }
@@ -0,0 +1,35 @@
1
+ syntax = "proto3";
2
+
3
+ message Message {
4
+ enum MessageType {
5
+ DIAL = 0;
6
+ DIAL_RESPONSE = 1;
7
+ }
8
+
9
+ enum ResponseStatus {
10
+ OK = 0;
11
+ E_DIAL_ERROR = 100;
12
+ E_DIAL_REFUSED = 101;
13
+ E_BAD_REQUEST = 200;
14
+ E_INTERNAL_ERROR = 300;
15
+ }
16
+
17
+ message PeerInfo {
18
+ optional bytes id = 1;
19
+ repeated bytes addrs = 2;
20
+ }
21
+
22
+ message Dial {
23
+ optional PeerInfo peer = 1;
24
+ }
25
+
26
+ message DialResponse {
27
+ optional ResponseStatus status = 1;
28
+ optional string statusText = 2;
29
+ optional bytes addr = 3;
30
+ }
31
+
32
+ optional MessageType type = 1;
33
+ optional Dial dial = 2;
34
+ optional DialResponse dialResponse = 3;
35
+ }