@libp2p/mdns 1.0.0 → 1.0.3

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.
@@ -0,0 +1,81 @@
1
+ import type { PeerInfo } from '@libp2p/interfaces/peer-info'
2
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
3
+ import { logger } from '@libp2p/logger'
4
+ import { peerIdFromString } from '@libp2p/peer-id'
5
+ import { Multiaddr } from '@multiformats/multiaddr'
6
+ import type { Answer } from 'dns-packet'
7
+ import { SERVICE_TAG_LOCAL } from './constants.js'
8
+
9
+ const log = logger('libp2p:mdns:compat:utils')
10
+
11
+ export function findPeerInfoInAnswers (answers: Answer[], ourPeerId: PeerId): PeerInfo | undefined {
12
+ const ptrRecord = answers.find(a => a.type === 'PTR' && a.name === SERVICE_TAG_LOCAL)
13
+
14
+ // Only deal with responses for our service tag
15
+ if (ptrRecord == null) {
16
+ return
17
+ }
18
+
19
+ log.trace('got response', SERVICE_TAG_LOCAL)
20
+
21
+ const txtRecord = answers.find(a => a.type === 'TXT')
22
+ if (txtRecord == null || txtRecord.type !== 'TXT') {
23
+ log('missing TXT record in response')
24
+ return
25
+ }
26
+
27
+ let peerIdStr: string
28
+ try {
29
+ peerIdStr = txtRecord.data[0].toString()
30
+ } catch (err) {
31
+ log('failed to extract peer ID from TXT record data', txtRecord, err)
32
+ return
33
+ }
34
+
35
+ let peerId: PeerId
36
+ try {
37
+ peerId = peerIdFromString(peerIdStr)
38
+ } catch (err) {
39
+ log('failed to create peer ID from TXT record data', peerIdStr, err)
40
+ return
41
+ }
42
+
43
+ if (ourPeerId.equals(peerId)) {
44
+ log('ignoring reply to myself')
45
+ return
46
+ }
47
+
48
+ const multiaddrs: Multiaddr[] = []
49
+ const hosts: { A: Record<string, string>, AAAA: Record<string, string> } = {
50
+ A: {},
51
+ AAAA: {}
52
+ }
53
+
54
+ answers.forEach(answer => {
55
+ if (answer.type === 'A') {
56
+ hosts.A[answer.name] = answer.data
57
+ }
58
+
59
+ if (answer.type === 'AAAA') {
60
+ hosts.AAAA[answer.name] = answer.data
61
+ }
62
+ })
63
+
64
+ answers.forEach(answer => {
65
+ if (answer.type === 'SRV') {
66
+ if (hosts.A[answer.data.target] != null) {
67
+ multiaddrs.push(new Multiaddr(`/ip4/${hosts.A[answer.data.target]}/tcp/${answer.data.port}/p2p/${peerId.toString()}`))
68
+ } else if (hosts.AAAA[answer.data.target] != null) {
69
+ multiaddrs.push(new Multiaddr(`/ip6/${hosts.AAAA[answer.data.target]}/tcp/${answer.data.port}/p2p/${peerId.toString()}`))
70
+ } else {
71
+ multiaddrs.push(new Multiaddr(`/dnsaddr/${answer.data.target}/tcp/${answer.data.port}/p2p/${peerId.toString()}`))
72
+ }
73
+ }
74
+ })
75
+
76
+ return {
77
+ id: peerId,
78
+ multiaddrs,
79
+ protocols: []
80
+ }
81
+ }
package/src/index.ts CHANGED
@@ -3,26 +3,23 @@ import { CustomEvent, EventEmitter } from '@libp2p/interfaces'
3
3
  import { logger } from '@libp2p/logger'
4
4
  import * as query from './query.js'
5
5
  import { GoMulticastDNS } from './compat/index.js'
6
- import type { PeerId } from '@libp2p/interfaces/peer-id'
7
6
  import type { PeerDiscovery, PeerDiscoveryEvents } from '@libp2p/interfaces/peer-discovery'
8
- import type { Multiaddr } from '@multiformats/multiaddr'
9
- import type { PeerData } from '@libp2p/interfaces/peer-data'
7
+ import type { PeerInfo } from '@libp2p/interfaces/peer-info'
8
+ import { Components, Initializable } from '@libp2p/interfaces/components'
10
9
 
11
10
  const log = logger('libp2p:mdns')
12
11
 
13
12
  export interface MulticastDNSOptions {
14
- peerId: PeerId
15
13
  broadcast?: boolean
16
14
  interval?: number
17
15
  serviceTag?: string
18
16
  port?: number
19
- multiaddrs?: Multiaddr[]
20
17
  compat?: boolean
21
18
  compatQueryPeriod?: number
22
19
  compatQueryInterval?: number
23
20
  }
24
21
 
25
- export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery {
22
+ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Initializable {
26
23
  static tag = 'mdns'
27
24
 
28
25
  public mdns?: multicastDNS.MulticastDNS
@@ -31,24 +28,17 @@ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements P
31
28
  private readonly interval: number
32
29
  private readonly serviceTag: string
33
30
  private readonly port: number
34
- private readonly peerId: PeerId
35
- private readonly peerMultiaddrs: Multiaddr[] // TODO: update this when multiaddrs change?
36
- private _queryInterval: NodeJS.Timer | null
31
+ private _queryInterval: ReturnType<typeof setInterval> | null
37
32
  private readonly _goMdns?: GoMulticastDNS
33
+ private components: Components = new Components()
38
34
 
39
- constructor (options: MulticastDNSOptions) {
35
+ constructor (options: MulticastDNSOptions = {}) {
40
36
  super()
41
37
 
42
- if (options.peerId == null) {
43
- throw new Error('needs own PeerId to work')
44
- }
45
-
46
38
  this.broadcast = options.broadcast !== false
47
39
  this.interval = options.interval ?? (1e3 * 10)
48
40
  this.serviceTag = options.serviceTag ?? 'ipfs.local'
49
41
  this.port = options.port ?? 5353
50
- this.peerId = options.peerId
51
- this.peerMultiaddrs = options.multiaddrs ?? []
52
42
  this._queryInterval = null
53
43
  this._onPeer = this._onPeer.bind(this)
54
44
  this._onMdnsQuery = this._onMdnsQuery.bind(this)
@@ -56,8 +46,6 @@ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements P
56
46
 
57
47
  if (options.compat !== false) {
58
48
  this._goMdns = new GoMulticastDNS({
59
- multiaddrs: this.peerMultiaddrs,
60
- peerId: options.peerId,
61
49
  queryPeriod: options.compatQueryPeriod,
62
50
  queryInterval: options.compatQueryInterval
63
51
  })
@@ -65,6 +53,12 @@ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements P
65
53
  }
66
54
  }
67
55
 
56
+ init (components: Components): void {
57
+ this.components = components
58
+
59
+ this._goMdns?.init(components)
60
+ }
61
+
68
62
  isStarted () {
69
63
  return Boolean(this.mdns)
70
64
  }
@@ -95,29 +89,34 @@ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements P
95
89
  return
96
90
  }
97
91
 
98
- query.gotQuery(event, this.mdns, this.peerId, this.peerMultiaddrs, this.serviceTag, this.broadcast)
92
+ log.trace('received incoming mDNS query')
93
+ query.gotQuery(event, this.mdns, this.components.getPeerId(), this.components.getAddressManager().getAddresses(), this.serviceTag, this.broadcast)
99
94
  }
100
95
 
101
96
  _onMdnsResponse (event: multicastDNS.ResponsePacket) {
97
+ log.trace('received mDNS query response')
98
+
102
99
  try {
103
- const foundPeer = query.gotResponse(event, this.peerId, this.serviceTag)
100
+ const foundPeer = query.gotResponse(event, this.components.getPeerId(), this.serviceTag)
104
101
 
105
102
  if (foundPeer != null) {
106
- this.dispatchEvent(new CustomEvent('peer', {
103
+ log('discovered peer in mDNS qeury response %p', foundPeer.id)
104
+
105
+ this.dispatchEvent(new CustomEvent<PeerInfo>('peer', {
107
106
  detail: foundPeer
108
107
  }))
109
108
  }
110
109
  } catch (err) {
111
- log('Error processing peer response', err)
110
+ log.error('Error processing peer response', err)
112
111
  }
113
112
  }
114
113
 
115
- _onPeer (evt: CustomEvent<PeerData>) {
114
+ _onPeer (evt: CustomEvent<PeerInfo>) {
116
115
  if (this.mdns == null) {
117
116
  return
118
117
  }
119
118
 
120
- this.dispatchEvent(new CustomEvent('peer', {
119
+ this.dispatchEvent(new CustomEvent<PeerInfo>('peer', {
121
120
  detail: evt.detail
122
121
  }))
123
122
  }
package/src/query.ts CHANGED
@@ -1,17 +1,18 @@
1
1
  import os from 'os'
2
2
  import { logger } from '@libp2p/logger'
3
- import { Multiaddr, MultiaddrObject } from '@multiformats/multiaddr'
4
- import { base58btc } from 'multiformats/bases/base58'
5
- import { PeerId } from '@libp2p/peer-id'
6
- import type { PeerData } from '@libp2p/interfaces/peer-data'
3
+ import { Multiaddr, MultiaddrObject, protocols } from '@multiformats/multiaddr'
4
+ import { peerIdFromString } from '@libp2p/peer-id'
5
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
6
+ import type { PeerInfo } from '@libp2p/interfaces/peer-info'
7
7
  import type { MulticastDNS, ResponsePacket, QueryPacket } from 'multicast-dns'
8
8
  import type { SrvAnswer, StringAnswer, TxtAnswer, Answer } from 'dns-packet'
9
9
 
10
- const log = logger('libp2p:mdns')
10
+ const log = logger('libp2p:mdns:query')
11
11
 
12
12
  export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: number) {
13
13
  const query = () => {
14
14
  log('query', serviceTag)
15
+
15
16
  mdns.query({
16
17
  questions: [{
17
18
  name: serviceTag,
@@ -33,7 +34,7 @@ interface Answers {
33
34
  aaaa: StringAnswer[]
34
35
  }
35
36
 
36
- export function gotResponse (rsp: ResponsePacket, localPeerId: PeerId, serviceTag: string): PeerData | undefined {
37
+ export function gotResponse (rsp: ResponsePacket, localPeerId: PeerId, serviceTag: string): PeerInfo | undefined {
37
38
  if (rsp.answers == null) {
38
39
  return
39
40
  }
@@ -81,14 +82,16 @@ export function gotResponse (rsp: ResponsePacket, localPeerId: PeerId, serviceTa
81
82
  }
82
83
  })
83
84
 
84
- if (localPeerId.toString(base58btc) === b58Id) {
85
+ if (localPeerId.toString() === b58Id) {
85
86
  return // replied to myself, ignore
86
87
  }
87
88
 
88
- log('peer found -', b58Id)
89
+ const id = peerIdFromString(b58Id)
90
+
91
+ log('peer found %p', id)
89
92
 
90
93
  return {
91
- id: PeerId.fromString(b58Id),
94
+ id,
92
95
  multiaddrs,
93
96
  protocols: []
94
97
  }
@@ -96,11 +99,12 @@ export function gotResponse (rsp: ResponsePacket, localPeerId: PeerId, serviceTa
96
99
 
97
100
  export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId, multiaddrs: Multiaddr[], serviceTag: string, broadcast: boolean) {
98
101
  if (!broadcast) {
102
+ log('not responding to mDNS query as broadcast mode is false')
99
103
  return
100
104
  }
101
105
 
102
106
  const addresses: MultiaddrObject[] = multiaddrs.reduce<MultiaddrObject[]>((acc, addr) => {
103
- if (addr.isThinWaistAddress()) {
107
+ if (addr.decapsulateCode(protocols('p2p').code).isThinWaistAddress()) {
104
108
  acc.push(addr.toOptions())
105
109
  }
106
110
  return acc
@@ -108,6 +112,7 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId,
108
112
 
109
113
  // Only announce TCP for now
110
114
  if (addresses.length === 0) {
115
+ log('no thin waist addresses present, cannot respond to query')
111
116
  return
112
117
  }
113
118
 
@@ -119,14 +124,14 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId,
119
124
  type: 'PTR',
120
125
  class: 'IN',
121
126
  ttl: 120,
122
- data: peerId.toString(base58btc) + '.' + serviceTag
127
+ data: peerId.toString() + '.' + serviceTag
123
128
  })
124
129
 
125
130
  // Only announce TCP multiaddrs for now
126
131
  const port = addresses[0].port
127
132
 
128
133
  answers.push({
129
- name: peerId.toString(base58btc) + '.' + serviceTag,
134
+ name: peerId.toString() + '.' + serviceTag,
130
135
  type: 'SRV',
131
136
  class: 'IN',
132
137
  ttl: 120,
@@ -139,11 +144,11 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId,
139
144
  })
140
145
 
141
146
  answers.push({
142
- name: peerId.toString(base58btc) + '.' + serviceTag,
147
+ name: peerId.toString() + '.' + serviceTag,
143
148
  type: 'TXT',
144
149
  class: 'IN',
145
150
  ttl: 120,
146
- data: peerId.toString(base58btc)
151
+ data: peerId.toString()
147
152
  })
148
153
 
149
154
  addresses.forEach((addr) => {